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