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