• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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