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