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.fingerprint.hidl;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.app.trust.TrustManager;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.hardware.fingerprint.FingerprintManager;
25 import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
26 import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
27 import android.hardware.fingerprint.FingerprintSensorProperties;
28 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
29 import android.hardware.fingerprint.IUdfpsOverlayController;
30 import android.os.Handler;
31 import android.os.IBinder;
32 import android.os.Looper;
33 import android.os.RemoteException;
34 import android.os.UserHandle;
35 import android.provider.Settings;
36 import android.util.Slog;
37 import android.util.SparseBooleanArray;
38 
39 import com.android.internal.R;
40 import com.android.server.biometrics.sensors.AuthenticationConsumer;
41 import com.android.server.biometrics.sensors.BaseClientMonitor;
42 import com.android.server.biometrics.sensors.BiometricScheduler;
43 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
44 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
45 import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
46 import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
47 
48 import java.util.ArrayList;
49 import java.util.List;
50 import java.util.Random;
51 
52 /**
53  * A mockable/testable provider of the {@link android.hardware.biometrics.fingerprint.V2_3} HIDL
54  * interface. This class is intended simulate UDFPS logic for devices that do not have an actual
55  * fingerprint@2.3 HAL (where UDFPS starts to become supported)
56  *
57  * UDFPS "accept" can only happen within a set amount of time after a sensor authentication. This is
58  * specified by {@link MockHalResultController#AUTH_VALIDITY_MS}. Touches after this duration will
59  * be treated as "reject".
60  *
61  * This class provides framework logic to emulate, for testing only, the UDFPS functionalies below:
62  *
63  * 1) IF either A) the caller is keyguard, and the device is not in a trusted state (authenticated
64  *    via biometric sensor or unlocked with a trust agent {@see android.app.trust.TrustManager}, OR
65  *    B) the caller is not keyguard, and regardless of trusted state, AND (following applies to both
66  *    (A) and (B) above) {@link FingerprintManager#onFingerDown(int, int, float, float)} is
67  *    received, this class will respond with {@link AuthenticationCallback#onAuthenticationFailed()}
68  *    after a tunable flat_time + variance_time.
69  *
70  *    In the case above (1), callers must not receive a successful authentication event here because
71  *    the sensor has not actually been authenticated.
72  *
73  * 2) IF A) the caller is keyguard and the device is not in a trusted state, OR B) the caller is not
74  *    keyguard and regardless of trusted state, AND (following applies to both (A) and (B)) the
75  *    sensor is touched and the fingerprint is accepted by the HAL, and then
76  *    {@link FingerprintManager#onFingerDown(int, int, float, float)} is received, this class will
77  *    respond with {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)}
78  *    after a tunable flat_time + variance_time. Note that the authentication callback from the
79  *    sensor is held until {@link FingerprintManager#onFingerDown(int, int, float, float)} is
80  *    invoked.
81  *
82  *    In the case above (2), callers can receive a successful authentication callback because the
83  *    real sensor was authenticated. Note that even though the real sensor was touched, keyguard
84  *    fingerprint authentication does not put keyguard into a trusted state because the
85  *    authentication callback is held until onFingerDown was invoked. This allows callers such as
86  *    keyguard to simulate a realistic path.
87  *
88  * 3) IF the caller is keyguard AND the device in a trusted state and then
89  *    {@link FingerprintManager#onFingerDown(int, int, float, float)} is received, this class will
90  *    respond with {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)}
91  *    after a tunable flat_time + variance time.
92  *
93  *    In the case above (3), since the device is already unlockable via trust agent, it's fine to
94  *    simulate the successful auth path. Non-keyguard clients will fall into either (1) or (2)
95  *    above.
96  *
97  *  This class currently does not simulate false rejection. Conversely, this class relies on the
98  *  real hardware sensor so does not affect false acceptance.
99  */
100 @SuppressWarnings("deprecation")
101 public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManager.TrustListener {
102 
103     private static final String TAG = "Fingerprint21UdfpsMock";
104 
105     // Secure setting integer. If true, the system will load this class to enable udfps testing.
106     public static final String CONFIG_ENABLE_TEST_UDFPS =
107             "com.android.server.biometrics.sensors.fingerprint.test_udfps.enable";
108     // Secure setting integer. A fixed duration intended to simulate something like the duration
109     // required for image capture.
110     private static final String CONFIG_AUTH_DELAY_PT1 =
111             "com.android.server.biometrics.sensors.fingerprint.test_udfps.auth_delay_pt1";
112     // Secure setting integer. A fixed duration intended to simulate something like the duration
113     // required for template matching to complete.
114     private static final String CONFIG_AUTH_DELAY_PT2 =
115             "com.android.server.biometrics.sensors.fingerprint.test_udfps.auth_delay_pt2";
116     // Secure setting integer. A random value between [-randomness, randomness] will be added to the
117     // capture delay above for each accept/reject.
118     private static final String CONFIG_AUTH_DELAY_RANDOMNESS =
119             "com.android.server.biometrics.sensors.fingerprint.test_udfps.auth_delay_randomness";
120 
121     private static final int DEFAULT_AUTH_DELAY_PT1_MS = 300;
122     private static final int DEFAULT_AUTH_DELAY_PT2_MS = 400;
123     private static final int DEFAULT_AUTH_DELAY_RANDOMNESS_MS = 100;
124 
125     @NonNull private final TestableBiometricScheduler mScheduler;
126     @NonNull private final Handler mHandler;
127     @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
128     @NonNull private final MockHalResultController mMockHalResultController;
129     @NonNull private final TrustManager mTrustManager;
130     @NonNull private final SparseBooleanArray mUserHasTrust;
131     @NonNull private final Random mRandom;
132     @NonNull private final FakeRejectRunnable mFakeRejectRunnable;
133     @NonNull private final FakeAcceptRunnable mFakeAcceptRunnable;
134     @NonNull private final RestartAuthRunnable mRestartAuthRunnable;
135 
136     private static class TestableBiometricScheduler extends BiometricScheduler {
137         @NonNull private Fingerprint21UdfpsMock mFingerprint21;
138 
TestableBiometricScheduler(@onNull String tag, @NonNull Handler handler, @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher)139         TestableBiometricScheduler(@NonNull String tag, @NonNull Handler handler,
140                 @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
141             super(tag, BiometricScheduler.SENSOR_TYPE_FP_OTHER, gestureAvailabilityDispatcher);
142         }
143 
init(@onNull Fingerprint21UdfpsMock fingerprint21)144         void init(@NonNull Fingerprint21UdfpsMock fingerprint21) {
145             mFingerprint21 = fingerprint21;
146         }
147     }
148 
149     /**
150      * All of the mocking/testing should happen in here. This way we don't need to modify the
151      * {@link BaseClientMonitor} implementations and can run the
152      * real path there.
153      */
154     private static class MockHalResultController extends HalResultController {
155 
156         // Duration for which a sensor authentication can be treated as UDFPS success.
157         private static final int AUTH_VALIDITY_MS = 10 * 1000; // 10 seconds
158 
159         static class LastAuthArgs {
160             @NonNull final AuthenticationConsumer lastAuthenticatedClient;
161             final long deviceId;
162             final int fingerId;
163             final int groupId;
164             @Nullable final ArrayList<Byte> token;
165 
LastAuthArgs(@onNull AuthenticationConsumer authenticationConsumer, long deviceId, int fingerId, int groupId, @Nullable ArrayList<Byte> token)166             LastAuthArgs(@NonNull AuthenticationConsumer authenticationConsumer, long deviceId,
167                     int fingerId, int groupId, @Nullable ArrayList<Byte> token) {
168                 lastAuthenticatedClient = authenticationConsumer;
169                 this.deviceId = deviceId;
170                 this.fingerId = fingerId;
171                 this.groupId = groupId;
172                 if (token == null) {
173                     this.token = null;
174                 } else {
175                     // Store a copy so the owner can be GC'd
176                     this.token = new ArrayList<>(token);
177                 }
178             }
179         }
180 
181         // Initialized after the constructor, but before it's ever used.
182         @NonNull private RestartAuthRunnable mRestartAuthRunnable;
183         @NonNull private Fingerprint21UdfpsMock mFingerprint21;
184         @Nullable private LastAuthArgs mLastAuthArgs;
185 
MockHalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler, @NonNull BiometricScheduler scheduler)186         MockHalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler,
187                 @NonNull BiometricScheduler scheduler) {
188             super(sensorId, context, handler, scheduler);
189         }
190 
init(@onNull RestartAuthRunnable restartAuthRunnable, @NonNull Fingerprint21UdfpsMock fingerprint21)191         void init(@NonNull RestartAuthRunnable restartAuthRunnable,
192                 @NonNull Fingerprint21UdfpsMock fingerprint21) {
193             mRestartAuthRunnable = restartAuthRunnable;
194             mFingerprint21 = fingerprint21;
195         }
196 
getLastAuthenticatedClient()197         @Nullable AuthenticationConsumer getLastAuthenticatedClient() {
198             return mLastAuthArgs != null ? mLastAuthArgs.lastAuthenticatedClient : null;
199         }
200 
201         /**
202          * Intercepts the HAL authentication and holds it until the UDFPS simulation decides
203          * that authentication finished.
204          */
205         @Override
onAuthenticated(long deviceId, int fingerId, int groupId, ArrayList<Byte> token)206         public void onAuthenticated(long deviceId, int fingerId, int groupId,
207                 ArrayList<Byte> token) {
208             mHandler.post(() -> {
209                 final BaseClientMonitor client = mScheduler.getCurrentClient();
210                 if (!(client instanceof AuthenticationConsumer)) {
211                     Slog.e(TAG, "Non authentication consumer: " + client);
212                     return;
213                 }
214 
215                 final boolean accepted = fingerId != 0;
216                 if (accepted) {
217                     mFingerprint21.setDebugMessage("Finger accepted");
218                 } else {
219                     mFingerprint21.setDebugMessage("Finger rejected");
220                 }
221 
222                 final AuthenticationConsumer authenticationConsumer =
223                         (AuthenticationConsumer) client;
224                 mLastAuthArgs = new LastAuthArgs(authenticationConsumer, deviceId, fingerId,
225                         groupId, token);
226 
227                 // Remove any existing restart runnbables since auth just started, and put a new
228                 // one on the queue.
229                 mHandler.removeCallbacks(mRestartAuthRunnable);
230                 mRestartAuthRunnable.setLastAuthReference(authenticationConsumer);
231                 mHandler.postDelayed(mRestartAuthRunnable, AUTH_VALIDITY_MS);
232             });
233         }
234 
235         /**
236          * Calls through to the real interface and notifies clients of accept/reject.
237          */
sendAuthenticated(long deviceId, int fingerId, int groupId, ArrayList<Byte> token)238         void sendAuthenticated(long deviceId, int fingerId, int groupId,
239                 ArrayList<Byte> token) {
240             Slog.d(TAG, "sendAuthenticated: " + (fingerId != 0));
241             mFingerprint21.setDebugMessage("Udfps match: " + (fingerId != 0));
242             super.onAuthenticated(deviceId, fingerId, groupId, token);
243         }
244     }
245 
newInstance(@onNull Context context, @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher)246     public static Fingerprint21UdfpsMock newInstance(@NonNull Context context,
247             @NonNull FingerprintStateCallback fingerprintStateCallback,
248             @NonNull FingerprintSensorPropertiesInternal sensorProps,
249             @NonNull LockoutResetDispatcher lockoutResetDispatcher,
250             @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
251         Slog.d(TAG, "Creating Fingerprint23Mock!");
252 
253         final Handler handler = new Handler(Looper.getMainLooper());
254         final TestableBiometricScheduler scheduler =
255                 new TestableBiometricScheduler(TAG, handler, gestureAvailabilityDispatcher);
256         final MockHalResultController controller =
257                 new MockHalResultController(sensorProps.sensorId, context, handler, scheduler);
258         return new Fingerprint21UdfpsMock(context, fingerprintStateCallback, sensorProps, scheduler,
259                 handler, lockoutResetDispatcher, controller);
260     }
261 
262     private static abstract class FakeFingerRunnable implements Runnable {
263         private long mFingerDownTime;
264         private int mCaptureDuration;
265 
266         /**
267          * @param fingerDownTime System time when onFingerDown occurred
268          * @param captureDuration Duration that the finger needs to be down for
269          */
setSimulationTime(long fingerDownTime, int captureDuration)270         void setSimulationTime(long fingerDownTime, int captureDuration) {
271             mFingerDownTime = fingerDownTime;
272             mCaptureDuration = captureDuration;
273         }
274 
275         @SuppressWarnings("BooleanMethodIsAlwaysInverted")
isImageCaptureComplete()276         boolean isImageCaptureComplete() {
277             return System.currentTimeMillis() - mFingerDownTime > mCaptureDuration;
278         }
279     }
280 
281     private final class FakeRejectRunnable extends FakeFingerRunnable {
282         @Override
run()283         public void run() {
284             mMockHalResultController.sendAuthenticated(0, 0, 0, null);
285         }
286     }
287 
288     private final class FakeAcceptRunnable extends FakeFingerRunnable {
289         @Override
run()290         public void run() {
291             if (mMockHalResultController.mLastAuthArgs == null) {
292                 // This can happen if the user has trust agents enabled, which make lockscreen
293                 // dismissable. Send a fake non-zero (accept) finger.
294                 Slog.d(TAG, "Sending fake finger");
295                 mMockHalResultController.sendAuthenticated(1 /* deviceId */,
296                         1 /* fingerId */, 1 /* groupId */, null /* token */);
297             } else {
298                 mMockHalResultController.sendAuthenticated(
299                         mMockHalResultController.mLastAuthArgs.deviceId,
300                         mMockHalResultController.mLastAuthArgs.fingerId,
301                         mMockHalResultController.mLastAuthArgs.groupId,
302                         mMockHalResultController.mLastAuthArgs.token);
303             }
304         }
305     }
306 
307     /**
308      * The fingerprint HAL allows multiple (5) fingerprint attempts per HIDL invocation of the
309      * authenticate method. However, valid fingerprint authentications are invalidated after
310      * {@link MockHalResultController#AUTH_VALIDITY_MS}, meaning UDFPS touches will be reported as
311      * rejects if touched after that duration. However, since a valid fingerprint was detected, the
312      * HAL and FingerprintService will not look for subsequent fingerprints.
313      *
314      * In order to keep the FingerprintManager API consistent (that multiple fingerprint attempts
315      * are allowed per auth lifecycle), we internally cancel and restart authentication so that the
316      * sensor is responsive again.
317      */
318     private static final class RestartAuthRunnable implements Runnable {
319         @NonNull private final Fingerprint21UdfpsMock mFingerprint21;
320         @NonNull private final TestableBiometricScheduler mScheduler;
321 
322         // Store a reference to the auth consumer that should be invalidated.
323         private AuthenticationConsumer mLastAuthConsumer;
324 
RestartAuthRunnable(@onNull Fingerprint21UdfpsMock fingerprint21, @NonNull TestableBiometricScheduler scheduler)325         RestartAuthRunnable(@NonNull Fingerprint21UdfpsMock fingerprint21,
326                 @NonNull TestableBiometricScheduler scheduler) {
327             mFingerprint21 = fingerprint21;
328             mScheduler = scheduler;
329         }
330 
setLastAuthReference(AuthenticationConsumer lastAuthConsumer)331         void setLastAuthReference(AuthenticationConsumer lastAuthConsumer) {
332             mLastAuthConsumer = lastAuthConsumer;
333         }
334 
335         @Override
run()336         public void run() {
337             final BaseClientMonitor client = mScheduler.getCurrentClient();
338 
339             // We don't care about FingerprintDetectClient, since accept/rejects are both OK. UDFPS
340             // rejects will just simulate the path where non-enrolled fingers are presented.
341             if (!(client instanceof FingerprintAuthenticationClient)) {
342                 Slog.e(TAG, "Non-FingerprintAuthenticationClient client: " + client);
343                 return;
344             }
345 
346             // Perhaps the runnable is stale, or the user stopped/started auth manually. Do not
347             // restart auth in this case.
348             if (client != mLastAuthConsumer) {
349                 Slog.e(TAG, "Current client: " + client
350                         + " does not match mLastAuthConsumer: " + mLastAuthConsumer);
351                 return;
352             }
353 
354             Slog.d(TAG, "Restarting auth, current: " + client);
355             mFingerprint21.setDebugMessage("Auth timed out");
356 
357             final FingerprintAuthenticationClient authClient =
358                     (FingerprintAuthenticationClient) client;
359             // Store the authClient parameters so it can be rescheduled
360             final IBinder token = client.getToken();
361             final long operationId = authClient.getOperationId();
362             final int user = client.getTargetUserId();
363             final int cookie = client.getCookie();
364             final ClientMonitorCallbackConverter listener = client.getListener();
365             final String opPackageName = client.getOwnerString();
366             final boolean restricted = authClient.isRestricted();
367             final int statsClient = client.getStatsClient();
368             final boolean isKeyguard = authClient.isKeyguard();
369 
370             // Don't actually send cancel() to the HAL, since successful auth already finishes
371             // HAL authenticate() lifecycle. Just
372             mScheduler.getInternalCallback().onClientFinished(client, true /* success */);
373 
374             // Schedule this only after we invoke onClientFinished for the previous client, so that
375             // internal preemption logic is not run.
376             mFingerprint21.scheduleAuthenticate(mFingerprint21.mSensorProperties.sensorId, token,
377                     operationId, user, cookie, listener, opPackageName, restricted, statsClient,
378                     isKeyguard);
379         }
380     }
381 
Fingerprint21UdfpsMock(@onNull Context context, @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull TestableBiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull MockHalResultController controller)382     private Fingerprint21UdfpsMock(@NonNull Context context,
383             @NonNull FingerprintStateCallback fingerprintStateCallback,
384             @NonNull FingerprintSensorPropertiesInternal sensorProps,
385             @NonNull TestableBiometricScheduler scheduler,
386             @NonNull Handler handler,
387             @NonNull LockoutResetDispatcher lockoutResetDispatcher,
388             @NonNull MockHalResultController controller) {
389         super(context, fingerprintStateCallback, sensorProps, scheduler, handler,
390                 lockoutResetDispatcher, controller);
391         mScheduler = scheduler;
392         mScheduler.init(this);
393         mHandler = handler;
394         // resetLockout is controlled by the framework, so hardwareAuthToken is not required
395         final boolean resetLockoutRequiresHardwareAuthToken = false;
396         final int maxTemplatesAllowed = mContext.getResources()
397                 .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser);
398         mSensorProperties = new FingerprintSensorPropertiesInternal(sensorProps.sensorId,
399                 sensorProps.sensorStrength, maxTemplatesAllowed, sensorProps.componentInfo,
400                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
401                 resetLockoutRequiresHardwareAuthToken, sensorProps.getAllLocations());
402         mMockHalResultController = controller;
403         mUserHasTrust = new SparseBooleanArray();
404         mTrustManager = context.getSystemService(TrustManager.class);
405         mTrustManager.registerTrustListener(this);
406         mRandom = new Random();
407         mFakeRejectRunnable = new FakeRejectRunnable();
408         mFakeAcceptRunnable = new FakeAcceptRunnable();
409         mRestartAuthRunnable = new RestartAuthRunnable(this, mScheduler);
410 
411         // We can't initialize this during MockHalresultController's constructor due to a circular
412         // dependency.
413         mMockHalResultController.init(mRestartAuthRunnable, this);
414     }
415 
416     @Override
onTrustChanged(boolean enabled, int userId, int flags)417     public void onTrustChanged(boolean enabled, int userId, int flags) {
418         mUserHasTrust.put(userId, enabled);
419     }
420 
421     @Override
onTrustManagedChanged(boolean enabled, int userId)422     public void onTrustManagedChanged(boolean enabled, int userId) {
423 
424     }
425 
426     @Override
onTrustError(CharSequence message)427     public void onTrustError(CharSequence message) {
428 
429     }
430 
431     @Override
432     @NonNull
getSensorProperties()433     public List<FingerprintSensorPropertiesInternal> getSensorProperties() {
434         final List<FingerprintSensorPropertiesInternal> properties = new ArrayList<>();
435         properties.add(mSensorProperties);
436         return properties;
437     }
438 
439     @Override
onPointerDown(int sensorId, int x, int y, float minor, float major)440     public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
441         mHandler.post(() -> {
442             Slog.d(TAG, "onFingerDown");
443             final AuthenticationConsumer lastAuthenticatedConsumer =
444                     mMockHalResultController.getLastAuthenticatedClient();
445             final BaseClientMonitor currentScheduledClient = mScheduler.getCurrentClient();
446 
447             if (currentScheduledClient == null) {
448                 Slog.d(TAG, "Not authenticating");
449                 return;
450             }
451 
452             mHandler.removeCallbacks(mFakeRejectRunnable);
453             mHandler.removeCallbacks(mFakeAcceptRunnable);
454 
455             // The sensor was authenticated, is still the currently scheduled client, and the
456             // user touched the UDFPS affordance. Pretend that auth succeeded.
457             final boolean authenticatedClientIsCurrent = lastAuthenticatedConsumer != null
458                     && lastAuthenticatedConsumer == currentScheduledClient;
459             // User is unlocked on keyguard via Trust Agent
460             final boolean keyguardAndTrusted;
461             if (currentScheduledClient instanceof FingerprintAuthenticationClient) {
462                 keyguardAndTrusted = ((FingerprintAuthenticationClient) currentScheduledClient)
463                         .isKeyguard()
464                         && mUserHasTrust.get(currentScheduledClient.getTargetUserId(), false);
465             } else {
466                 keyguardAndTrusted = false;
467             }
468 
469             final int captureDuration = getNewCaptureDuration();
470             final int matchingDuration = getMatchingDuration();
471             final int totalDuration = captureDuration + matchingDuration;
472             setDebugMessage("Duration: " + totalDuration
473                     + " (" + captureDuration + " + " + matchingDuration + ")");
474             if (authenticatedClientIsCurrent || keyguardAndTrusted) {
475                 mFakeAcceptRunnable.setSimulationTime(System.currentTimeMillis(), captureDuration);
476                 mHandler.postDelayed(mFakeAcceptRunnable, totalDuration);
477             } else if (currentScheduledClient instanceof AuthenticationConsumer) {
478                 // Something is authenticating but authentication has not succeeded yet. Pretend
479                 // that auth rejected.
480                 mFakeRejectRunnable.setSimulationTime(System.currentTimeMillis(), captureDuration);
481                 mHandler.postDelayed(mFakeRejectRunnable, totalDuration);
482             }
483         });
484     }
485 
486     @Override
onPointerUp(int sensorId)487     public void onPointerUp(int sensorId) {
488         mHandler.post(() -> {
489             Slog.d(TAG, "onFingerUp");
490 
491             // Only one of these can be on the handler at any given time (see onFingerDown). If
492             // image capture is not complete, send ACQUIRED_TOO_FAST and remove the runnable from
493             // the handler. Image capture (onFingerDown) needs to happen again.
494             if (mHandler.hasCallbacks(mFakeRejectRunnable)
495                     && !mFakeRejectRunnable.isImageCaptureComplete()) {
496                 mHandler.removeCallbacks(mFakeRejectRunnable);
497                 mMockHalResultController.onAcquired(0 /* deviceId */,
498                         FingerprintManager.FINGERPRINT_ACQUIRED_TOO_FAST,
499                         0 /* vendorCode */);
500             } else if (mHandler.hasCallbacks(mFakeAcceptRunnable)
501                     && !mFakeAcceptRunnable.isImageCaptureComplete()) {
502                 mHandler.removeCallbacks(mFakeAcceptRunnable);
503                 mMockHalResultController.onAcquired(0 /* deviceId */,
504                         FingerprintManager.FINGERPRINT_ACQUIRED_TOO_FAST,
505                         0 /* vendorCode */);
506             }
507         });
508     }
509 
getNewCaptureDuration()510     private int getNewCaptureDuration() {
511         final ContentResolver contentResolver = mContext.getContentResolver();
512         final int captureTime = Settings.Secure.getIntForUser(contentResolver,
513                 CONFIG_AUTH_DELAY_PT1,
514                 DEFAULT_AUTH_DELAY_PT1_MS,
515                 UserHandle.USER_CURRENT);
516         final int randomDelayRange = Settings.Secure.getIntForUser(contentResolver,
517                 CONFIG_AUTH_DELAY_RANDOMNESS,
518                 DEFAULT_AUTH_DELAY_RANDOMNESS_MS,
519                 UserHandle.USER_CURRENT);
520         final int randomDelay = mRandom.nextInt(randomDelayRange * 2) - randomDelayRange;
521 
522         // Must be at least 0
523         return Math.max(captureTime + randomDelay, 0);
524     }
525 
getMatchingDuration()526     private int getMatchingDuration() {
527         final int matchingTime = Settings.Secure.getIntForUser(mContext.getContentResolver(),
528                 CONFIG_AUTH_DELAY_PT2,
529                 DEFAULT_AUTH_DELAY_PT2_MS,
530                 UserHandle.USER_CURRENT);
531 
532         // Must be at least 0
533         return Math.max(matchingTime, 0);
534     }
535 
setDebugMessage(String message)536     private void setDebugMessage(String message) {
537         try {
538             final IUdfpsOverlayController controller = getUdfpsOverlayController();
539             // Things can happen before SysUI loads and sets the controller.
540             if (controller != null) {
541                 Slog.d(TAG, "setDebugMessage: " + message);
542                 controller.setDebugMessage(mSensorProperties.sensorId, message);
543             }
544         } catch (RemoteException e) {
545             Slog.e(TAG, "Remote exception when sending message: " + message, e);
546         }
547     }
548 }
549