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