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