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