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 Interruptable, 42 ErrorConsumer { 43 44 private static final String TAG = "Biometrics/AcquisitionClient"; 45 46 private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES = 47 VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK); 48 49 private static final VibrationEffect SUCCESS_VIBRATION_EFFECT = 50 VibrationEffect.get(VibrationEffect.EFFECT_CLICK); 51 private static final VibrationEffect ERROR_VIBRATION_EFFECT = 52 VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK); 53 54 private final PowerManager mPowerManager; 55 // If haptics should occur when auth result (success/reject) is known 56 protected final boolean mShouldVibrate; 57 private boolean mShouldSendErrorToClient = true; 58 private boolean mAlreadyCancelled; 59 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)60 public AcquisitionClient(@NonNull Context context, @NonNull Supplier<T> lazyDaemon, 61 @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, 62 @NonNull String owner, int cookie, int sensorId, boolean shouldVibrate, 63 @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext) { 64 super(context, lazyDaemon, token, listener, userId, owner, cookie, sensorId, 65 logger, biometricContext); 66 mPowerManager = context.getSystemService(PowerManager.class); 67 mShouldVibrate = shouldVibrate; 68 } 69 70 /** 71 * Stops the HAL operation specific to the ClientMonitor subclass. 72 */ stopHalOperation()73 protected abstract void stopHalOperation(); 74 75 @Override unableToStart()76 public void unableToStart() { 77 try { 78 getListener().onError(getSensorId(), getCookie(), 79 BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); 80 } catch (RemoteException e) { 81 Slog.e(TAG, "Unable to send error", e); 82 } 83 } 84 85 @Override onError(int errorCode, int vendorCode)86 public void onError(int errorCode, int vendorCode) { 87 // Errors from the HAL always finish the client 88 onErrorInternal(errorCode, vendorCode, true /* finish */); 89 } 90 91 /** 92 * Notifies the caller that the operation was canceled by the user. Note that the actual 93 * operation still needs to wait for the HAL to send ERROR_CANCELED. 94 */ onUserCanceled()95 public void onUserCanceled() { 96 Slog.d(TAG, "onUserCanceled"); 97 98 // Send USER_CANCELED, but do not finish. Wait for the HAL to respond with ERROR_CANCELED, 99 // which then finishes the AcquisitionClient's lifecycle. 100 onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED, 0 /* vendorCode */, 101 false /* finish */); 102 stopHalOperation(); 103 } 104 onErrorInternal(int errorCode, int vendorCode, boolean finish)105 protected void onErrorInternal(int errorCode, int vendorCode, boolean finish) { 106 Slog.d(TAG, "onErrorInternal code: " + errorCode + ", finish: " + finish); 107 108 // In some cases, the framework will send an error to the caller before a true terminal 109 // case (success, failure, or error) is received from the HAL (e.g. versions of fingerprint 110 // that do not handle lockout under the HAL. In these cases, ensure that the framework only 111 // sends errors once per ClientMonitor. 112 if (mShouldSendErrorToClient) { 113 getLogger().logOnError(getContext(), getOperationContext(), 114 errorCode, vendorCode, getTargetUserId()); 115 try { 116 if (getListener() != null) { 117 mShouldSendErrorToClient = false; 118 getListener().onError(getSensorId(), getCookie(), errorCode, vendorCode); 119 } 120 } catch (RemoteException e) { 121 Slog.w(TAG, "Failed to invoke sendError", e); 122 } 123 } 124 125 if (finish) { 126 if (mCallback == null) { 127 Slog.e(TAG, "Callback is null, perhaps the client hasn't been started yet?"); 128 } else { 129 mCallback.onClientFinished(this, false /* success */); 130 } 131 } 132 } 133 134 @Override cancel()135 public void cancel() { 136 if (mAlreadyCancelled) { 137 Slog.w(TAG, "Cancel was already requested"); 138 return; 139 } 140 141 stopHalOperation(); 142 mAlreadyCancelled = true; 143 } 144 145 @Override cancelWithoutStarting(@onNull ClientMonitorCallback callback)146 public void cancelWithoutStarting(@NonNull ClientMonitorCallback callback) { 147 Slog.d(TAG, "cancelWithoutStarting: " + this); 148 149 final int errorCode = BiometricConstants.BIOMETRIC_ERROR_CANCELED; 150 try { 151 if (getListener() != null) { 152 getListener().onError(getSensorId(), getCookie(), errorCode, 0 /* vendorCode */); 153 } 154 } catch (RemoteException e) { 155 Slog.w(TAG, "Failed to invoke sendError", e); 156 } 157 callback.onClientFinished(this, true /* success */); 158 } 159 160 /** 161 * Called when we get notification from the biometric's HAL that an image has been acquired. 162 * Common to authenticate and enroll. 163 * @param acquiredInfo info about the current image acquisition 164 */ onAcquired(int acquiredInfo, int vendorCode)165 public void onAcquired(int acquiredInfo, int vendorCode) { 166 // Default is to always send acquire messages to clients. 167 onAcquiredInternal(acquiredInfo, vendorCode, true /* shouldSend */); 168 } 169 onAcquiredInternal(int acquiredInfo, int vendorCode, boolean shouldSend)170 protected final void onAcquiredInternal(int acquiredInfo, int vendorCode, 171 boolean shouldSend) { 172 getLogger().logOnAcquired(getContext(), getOperationContext(), 173 acquiredInfo, vendorCode, getTargetUserId()); 174 if (DEBUG) { 175 Slog.v(TAG, "Acquired: " + acquiredInfo + " " + vendorCode 176 + ", shouldSend: " + shouldSend); 177 } 178 179 // Good scans will keep the device awake 180 if (acquiredInfo == BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) { 181 notifyUserActivity(); 182 } 183 184 try { 185 if (getListener() != null && shouldSend) { 186 getListener().onAcquired(getSensorId(), acquiredInfo, vendorCode); 187 } 188 } catch (RemoteException e) { 189 Slog.w(TAG, "Failed to invoke sendAcquired", e); 190 mCallback.onClientFinished(this, false /* success */); 191 } 192 } 193 notifyUserActivity()194 final void notifyUserActivity() { 195 long now = SystemClock.uptimeMillis(); 196 mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0); 197 } 198 vibrateSuccess()199 protected final void vibrateSuccess() { 200 Vibrator vibrator = getContext().getSystemService(Vibrator.class); 201 if (vibrator != null && mShouldVibrate) { 202 vibrator.vibrate(Process.myUid(), 203 getContext().getOpPackageName(), 204 SUCCESS_VIBRATION_EFFECT, 205 getClass().getSimpleName() + "::success", 206 HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES); 207 } 208 } 209 vibrateError()210 protected final void vibrateError() { 211 Vibrator vibrator = getContext().getSystemService(Vibrator.class); 212 if (vibrator != null && mShouldVibrate) { 213 vibrator.vibrate(Process.myUid(), 214 getContext().getOpPackageName(), 215 ERROR_VIBRATION_EFFECT, 216 getClass().getSimpleName() + "::error", 217 HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES); 218 } 219 } 220 } 221