1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.biometrics.sensors; 18 19 import android.annotation.NonNull; 20 import android.content.Context; 21 import android.hardware.biometrics.BiometricConstants; 22 import android.os.IBinder; 23 import android.os.PowerManager; 24 import android.os.Process; 25 import android.os.RemoteException; 26 import android.os.SystemClock; 27 import android.os.VibrationAttributes; 28 import android.os.VibrationEffect; 29 import android.os.Vibrator; 30 import android.util.Slog; 31 32 import com.android.server.biometrics.log.BiometricContext; 33 import com.android.server.biometrics.log.BiometricLogger; 34 35 import java.util.function.Supplier; 36 37 /** 38 * Abstract {@link HalClientMonitor} subclass that operations eligible/interested in acquisition 39 * messages should extend. 40 */ 41 public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implements ErrorConsumer { 42 43 private static final String TAG = "Biometrics/AcquisitionClient"; 44 45 private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES = 46 VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK); 47 48 private static final VibrationEffect SUCCESS_VIBRATION_EFFECT = 49 VibrationEffect.get(VibrationEffect.EFFECT_CLICK); 50 private static final VibrationEffect ERROR_VIBRATION_EFFECT = 51 VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK); 52 53 private final PowerManager mPowerManager; 54 // If haptics should occur when auth result (success/reject) is known 55 protected final boolean mShouldVibrate; 56 private boolean mShouldSendErrorToClient = true; 57 private boolean mAlreadyCancelled; 58 AcquisitionClient(@onNull Context context, @NonNull Supplier<T> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, int cookie, int sensorId, boolean shouldVibrate, @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext)59 public AcquisitionClient(@NonNull Context context, @NonNull Supplier<T> lazyDaemon, 60 @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, 61 @NonNull String owner, int cookie, int sensorId, boolean shouldVibrate, 62 @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext) { 63 super(context, lazyDaemon, token, listener, userId, owner, cookie, sensorId, 64 logger, biometricContext); 65 mPowerManager = context.getSystemService(PowerManager.class); 66 mShouldVibrate = shouldVibrate; 67 } 68 69 /** 70 * Stops the HAL operation specific to the ClientMonitor subclass. 71 */ stopHalOperation()72 protected abstract void stopHalOperation(); 73 74 @Override unableToStart()75 public void unableToStart() { 76 try { 77 getListener().onError(getSensorId(), getCookie(), 78 BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); 79 } catch (RemoteException e) { 80 Slog.e(TAG, "Unable to send error", e); 81 } 82 } 83 84 @Override onError(int errorCode, int vendorCode)85 public void onError(int errorCode, int vendorCode) { 86 // Errors from the HAL always finish the client 87 onErrorInternal(errorCode, vendorCode, true /* finish */); 88 } 89 90 /** 91 * Notifies the caller that the operation was canceled by the user. Note that the actual 92 * operation still needs to wait for the HAL to send ERROR_CANCELED. 93 */ onUserCanceled()94 public void onUserCanceled() { 95 Slog.d(TAG, "onUserCanceled"); 96 97 // Send USER_CANCELED, but do not finish. Wait for the HAL to respond with ERROR_CANCELED, 98 // which then finishes the AcquisitionClient's lifecycle. 99 onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED, 0 /* vendorCode */, 100 false /* finish */); 101 stopHalOperation(); 102 } 103 onErrorInternal(int errorCode, int vendorCode, boolean finish)104 protected void onErrorInternal(int errorCode, int vendorCode, boolean finish) { 105 Slog.d(TAG, "onErrorInternal code: " + errorCode + ", finish: " + finish); 106 107 // In some cases, the framework will send an error to the caller before a true terminal 108 // case (success, failure, or error) is received from the HAL (e.g. versions of fingerprint 109 // that do not handle lockout under the HAL. In these cases, ensure that the framework only 110 // sends errors once per ClientMonitor. 111 if (mShouldSendErrorToClient) { 112 getLogger().logOnError(getContext(), getOperationContext(), 113 errorCode, vendorCode, getTargetUserId()); 114 try { 115 if (getListener() != null) { 116 mShouldSendErrorToClient = false; 117 getListener().onError(getSensorId(), getCookie(), errorCode, vendorCode); 118 } 119 } catch (RemoteException e) { 120 Slog.w(TAG, "Failed to invoke sendError", e); 121 } 122 } 123 124 if (finish) { 125 if (mCallback == null) { 126 Slog.e(TAG, "Callback is null, perhaps the client hasn't been started yet?"); 127 } else { 128 mCallback.onClientFinished(this, false /* success */); 129 } 130 } 131 } 132 133 @Override cancel()134 public void cancel() { 135 if (mAlreadyCancelled) { 136 Slog.w(TAG, "Cancel was already requested"); 137 return; 138 } 139 140 stopHalOperation(); 141 mAlreadyCancelled = true; 142 } 143 144 @Override cancelWithoutStarting(@onNull ClientMonitorCallback callback)145 public void cancelWithoutStarting(@NonNull ClientMonitorCallback callback) { 146 Slog.d(TAG, "cancelWithoutStarting: " + this); 147 148 final int errorCode = BiometricConstants.BIOMETRIC_ERROR_CANCELED; 149 try { 150 if (getListener() != null) { 151 getListener().onError(getSensorId(), getCookie(), errorCode, 0 /* vendorCode */); 152 } 153 } catch (RemoteException e) { 154 Slog.w(TAG, "Failed to invoke sendError", e); 155 } 156 callback.onClientFinished(this, true /* success */); 157 } 158 159 /** 160 * Called when we get notification from the biometric's HAL that an image has been acquired. 161 * Common to authenticate and enroll. 162 * @param acquiredInfo info about the current image acquisition 163 */ onAcquired(int acquiredInfo, int vendorCode)164 public void onAcquired(int acquiredInfo, int vendorCode) { 165 // Default is to always send acquire messages to clients. 166 onAcquiredInternal(acquiredInfo, vendorCode, true /* shouldSend */); 167 } 168 onAcquiredInternal(int acquiredInfo, int vendorCode, boolean shouldSend)169 protected final void onAcquiredInternal(int acquiredInfo, int vendorCode, 170 boolean shouldSend) { 171 getLogger().logOnAcquired(getContext(), getOperationContext(), 172 acquiredInfo, vendorCode, getTargetUserId()); 173 if (DEBUG) { 174 Slog.v(TAG, "Acquired: " + acquiredInfo + " " + vendorCode 175 + ", shouldSend: " + shouldSend); 176 } 177 178 // Good scans will keep the device awake 179 if (acquiredInfo == BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) { 180 notifyUserActivity(); 181 } 182 183 try { 184 if (getListener() != null && shouldSend) { 185 getListener().onAcquired(getSensorId(), acquiredInfo, vendorCode); 186 } 187 } catch (RemoteException e) { 188 Slog.w(TAG, "Failed to invoke sendAcquired", e); 189 mCallback.onClientFinished(this, false /* success */); 190 } 191 } 192 notifyUserActivity()193 final void notifyUserActivity() { 194 long now = SystemClock.uptimeMillis(); 195 mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0); 196 } 197 vibrateSuccess()198 protected final void vibrateSuccess() { 199 Vibrator vibrator = getContext().getSystemService(Vibrator.class); 200 if (vibrator != null && mShouldVibrate) { 201 vibrator.vibrate(Process.myUid(), 202 getContext().getOpPackageName(), 203 SUCCESS_VIBRATION_EFFECT, 204 getClass().getSimpleName() + "::success", 205 HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES); 206 } 207 } 208 209 @Override isInterruptable()210 public boolean isInterruptable() { 211 return true; 212 } 213 isAlreadyCancelled()214 public boolean isAlreadyCancelled() { 215 return mAlreadyCancelled; 216 } 217 } 218