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; 18 19 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; 20 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; 21 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE; 22 import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT; 23 import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT; 24 25 import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_FACE_SCANNING; 26 import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_FP_SCANNING; 27 import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_SWITCHING; 28 import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_UNKNOWN; 29 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTHENTICATED_PENDING_SYSUI; 30 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED; 31 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_IDLE; 32 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PAUSED; 33 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PAUSED_RESUMING; 34 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PENDING_CONFIRM; 35 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED; 36 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED_UI_SHOWING; 37 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_CLIENT_DIED_CANCELLING; 38 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_ERROR_PENDING_SYSUI; 39 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_SHOWING_DEVICE_CREDENTIAL; 40 41 import android.annotation.IntDef; 42 import android.annotation.NonNull; 43 import android.annotation.Nullable; 44 import android.content.Context; 45 import android.hardware.biometrics.BiometricAuthenticator; 46 import android.hardware.biometrics.BiometricAuthenticator.Modality; 47 import android.hardware.biometrics.BiometricConstants; 48 import android.hardware.biometrics.BiometricManager; 49 import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode; 50 import android.hardware.biometrics.BiometricPrompt; 51 import android.hardware.biometrics.BiometricsProtoEnums; 52 import android.hardware.biometrics.IBiometricSensorReceiver; 53 import android.hardware.biometrics.IBiometricServiceReceiver; 54 import android.hardware.biometrics.IBiometricSysuiReceiver; 55 import android.hardware.biometrics.PromptInfo; 56 import android.hardware.face.FaceManager; 57 import android.hardware.fingerprint.FingerprintManager; 58 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 59 import android.os.IBinder; 60 import android.os.RemoteException; 61 import android.security.KeyStore; 62 import android.util.Slog; 63 64 import com.android.internal.annotations.VisibleForTesting; 65 import com.android.internal.statusbar.IStatusBarService; 66 import com.android.internal.util.FrameworkStatsLog; 67 68 import java.lang.annotation.Retention; 69 import java.lang.annotation.RetentionPolicy; 70 import java.util.Collection; 71 import java.util.List; 72 import java.util.Random; 73 import java.util.function.Function; 74 75 /** 76 * Class that defines the states of an authentication session invoked via 77 * {@link android.hardware.biometrics.BiometricPrompt}, as well as all of the necessary 78 * state information for such a session. 79 */ 80 public final class AuthSession implements IBinder.DeathRecipient { 81 private static final String TAG = "BiometricService/AuthSession"; 82 private static final boolean DEBUG = false; 83 84 /* 85 * Defined in biometrics.proto 86 */ 87 @IntDef({ 88 STATE_AUTH_IDLE, 89 STATE_AUTH_CALLED, 90 STATE_AUTH_STARTED, 91 STATE_AUTH_STARTED_UI_SHOWING, 92 STATE_AUTH_PAUSED, 93 STATE_AUTH_PAUSED_RESUMING, 94 STATE_AUTH_PENDING_CONFIRM, 95 STATE_AUTHENTICATED_PENDING_SYSUI, 96 STATE_ERROR_PENDING_SYSUI, 97 STATE_SHOWING_DEVICE_CREDENTIAL}) 98 @Retention(RetentionPolicy.SOURCE) 99 @interface SessionState {} 100 101 /** Defined in biometrics.proto */ 102 @IntDef({ 103 MULTI_SENSOR_STATE_UNKNOWN, 104 MULTI_SENSOR_STATE_FACE_SCANNING, 105 MULTI_SENSOR_STATE_FP_SCANNING}) 106 @Retention(RetentionPolicy.SOURCE) 107 @interface MultiSensorState {} 108 109 /** 110 * Notify the holder of the AuthSession that the caller/client's binder has died. The 111 * holder (BiometricService) should schedule {@link AuthSession#onClientDied()} to be run 112 * on its handler (instead of whatever thread invokes the death recipient callback). 113 */ 114 interface ClientDeathReceiver { onClientDied()115 void onClientDied(); 116 } 117 118 private final Context mContext; 119 private final IStatusBarService mStatusBarService; 120 private final IBiometricSysuiReceiver mSysuiReceiver; 121 private final KeyStore mKeyStore; 122 private final Random mRandom; 123 private final ClientDeathReceiver mClientDeathReceiver; 124 final PreAuthInfo mPreAuthInfo; 125 126 // The following variables are passed to authenticateInternal, which initiates the 127 // appropriate <Biometric>Services. 128 @VisibleForTesting final IBinder mToken; 129 // Info to be shown on BiometricDialog when all cookies are returned. 130 @VisibleForTesting final PromptInfo mPromptInfo; 131 private final long mOperationId; 132 private final int mUserId; 133 private final IBiometricSensorReceiver mSensorReceiver; 134 // Original receiver from BiometricPrompt. 135 private final IBiometricServiceReceiver mClientReceiver; 136 private final String mOpPackageName; 137 private final boolean mDebugEnabled; 138 private final List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties; 139 140 // The current state, which can be either idle, called, or started 141 private @SessionState int mState = STATE_AUTH_IDLE; 142 private @BiometricMultiSensorMode int mMultiSensorMode; 143 private @MultiSensorState int mMultiSensorState; 144 private int[] mSensors; 145 // For explicit confirmation, do not send to keystore until the user has confirmed 146 // the authentication. 147 private byte[] mTokenEscrow; 148 // Waiting for SystemUI to complete animation 149 private int mErrorEscrow; 150 private int mVendorCodeEscrow; 151 152 // Timestamp when authentication started 153 private long mStartTimeMs; 154 // Timestamp when hardware authentication occurred 155 private long mAuthenticatedTimeMs; 156 AuthSession(@onNull Context context, @NonNull IStatusBarService statusBarService, @NonNull IBiometricSysuiReceiver sysuiReceiver, @NonNull KeyStore keystore, @NonNull Random random, @NonNull ClientDeathReceiver clientDeathReceiver, @NonNull PreAuthInfo preAuthInfo, @NonNull IBinder token, long operationId, int userId, @NonNull IBiometricSensorReceiver sensorReceiver, @NonNull IBiometricServiceReceiver clientReceiver, @NonNull String opPackageName, @NonNull PromptInfo promptInfo, boolean debugEnabled, @NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties)157 AuthSession(@NonNull Context context, 158 @NonNull IStatusBarService statusBarService, 159 @NonNull IBiometricSysuiReceiver sysuiReceiver, 160 @NonNull KeyStore keystore, 161 @NonNull Random random, 162 @NonNull ClientDeathReceiver clientDeathReceiver, 163 @NonNull PreAuthInfo preAuthInfo, 164 @NonNull IBinder token, 165 long operationId, 166 int userId, 167 @NonNull IBiometricSensorReceiver sensorReceiver, 168 @NonNull IBiometricServiceReceiver clientReceiver, 169 @NonNull String opPackageName, 170 @NonNull PromptInfo promptInfo, 171 boolean debugEnabled, 172 @NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties) { 173 Slog.d(TAG, "Creating AuthSession with: " + preAuthInfo); 174 mContext = context; 175 mStatusBarService = statusBarService; 176 mSysuiReceiver = sysuiReceiver; 177 mKeyStore = keystore; 178 mRandom = random; 179 mClientDeathReceiver = clientDeathReceiver; 180 mPreAuthInfo = preAuthInfo; 181 mToken = token; 182 mOperationId = operationId; 183 mUserId = userId; 184 mSensorReceiver = sensorReceiver; 185 mClientReceiver = clientReceiver; 186 mOpPackageName = opPackageName; 187 mPromptInfo = promptInfo; 188 mDebugEnabled = debugEnabled; 189 mFingerprintSensorProperties = fingerprintSensorProperties; 190 191 try { 192 mClientReceiver.asBinder().linkToDeath(this, 0 /* flags */); 193 } catch (RemoteException e) { 194 Slog.w(TAG, "Unable to link to death"); 195 } 196 197 setSensorsToStateUnknown(); 198 } 199 200 @Override binderDied()201 public void binderDied() { 202 Slog.e(TAG, "Binder died, session: " + this); 203 mClientDeathReceiver.onClientDied(); 204 } 205 206 /** 207 * @return bitmask representing the modalities that are running or could be running for the 208 * current session. 209 */ getEligibleModalities()210 private @BiometricAuthenticator.Modality int getEligibleModalities() { 211 return mPreAuthInfo.getEligibleModalities(); 212 } 213 setSensorsToStateUnknown()214 private void setSensorsToStateUnknown() { 215 // Generate random cookies to pass to the services that should prepare to start 216 // authenticating. Store the cookie here and wait for all services to "ack" 217 // with the cookie. Once all cookies are received, we can show the prompt 218 // and let the services start authenticating. The cookie should be non-zero. 219 for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { 220 if (DEBUG) { 221 Slog.v(TAG, "set to unknown state sensor: " + sensor.id); 222 } 223 sensor.goToStateUnknown(); 224 } 225 } 226 setSensorsToStateWaitingForCookie()227 private void setSensorsToStateWaitingForCookie() throws RemoteException { 228 for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { 229 final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; 230 final boolean requireConfirmation = isConfirmationRequired(sensor); 231 232 if (DEBUG) { 233 Slog.v(TAG, "waiting for cooking for sensor: " + sensor.id); 234 } 235 sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId, 236 mUserId, mSensorReceiver, mOpPackageName, cookie, 237 mPromptInfo.isAllowBackgroundAuthentication()); 238 } 239 } 240 goToInitialState()241 void goToInitialState() throws RemoteException { 242 if (mPreAuthInfo.credentialAvailable && mPreAuthInfo.eligibleSensors.isEmpty()) { 243 // Only device credential should be shown. In this case, we don't need to wait, 244 // since LockSettingsService/Gatekeeper is always ready to check for credential. 245 // SystemUI invokes that path. 246 mState = STATE_SHOWING_DEVICE_CREDENTIAL; 247 mSensors = new int[0]; 248 mMultiSensorMode = BIOMETRIC_MULTI_SENSOR_DEFAULT; 249 mMultiSensorState = MULTI_SENSOR_STATE_UNKNOWN; 250 251 mStatusBarService.showAuthenticationDialog( 252 mPromptInfo, 253 mSysuiReceiver, 254 mSensors /* sensorIds */, 255 true /* credentialAllowed */, 256 false /* requireConfirmation */, 257 mUserId, 258 mOpPackageName, 259 mOperationId, 260 mMultiSensorMode); 261 } else if (!mPreAuthInfo.eligibleSensors.isEmpty()) { 262 // Some combination of biometric or biometric|credential is requested 263 setSensorsToStateWaitingForCookie(); 264 mState = STATE_AUTH_CALLED; 265 } else { 266 // No authenticators requested. This should never happen - an exception should have 267 // been thrown earlier in the pipeline. 268 throw new IllegalStateException("No authenticators requested"); 269 } 270 } 271 onCookieReceived(int cookie)272 void onCookieReceived(int cookie) { 273 for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { 274 sensor.goToStateCookieReturnedIfCookieMatches(cookie); 275 } 276 277 if (allCookiesReceived()) { 278 mStartTimeMs = System.currentTimeMillis(); 279 280 // Do not start fingerprint sensors until BiometricPrompt UI is shown. Otherwise, 281 // the affordance may be shown before the BP UI is finished animating in. 282 startAllPreparedSensorsExceptFingerprint(); 283 284 // No need to request the UI if we're coming from the paused state. 285 if (mState != STATE_AUTH_PAUSED_RESUMING) { 286 try { 287 // If any sensor requires confirmation, request it to be shown. 288 final boolean requireConfirmation = isConfirmationRequiredByAnyEligibleSensor(); 289 290 mSensors = new int[mPreAuthInfo.eligibleSensors.size()]; 291 for (int i = 0; i < mPreAuthInfo.eligibleSensors.size(); i++) { 292 mSensors[i] = mPreAuthInfo.eligibleSensors.get(i).id; 293 } 294 mMultiSensorMode = getMultiSensorModeForNewSession( 295 mPreAuthInfo.eligibleSensors); 296 mMultiSensorState = MULTI_SENSOR_STATE_UNKNOWN; 297 298 mStatusBarService.showAuthenticationDialog(mPromptInfo, 299 mSysuiReceiver, 300 mSensors, 301 mPreAuthInfo.shouldShowCredential(), 302 requireConfirmation, 303 mUserId, 304 mOpPackageName, 305 mOperationId, 306 mMultiSensorMode); 307 mState = STATE_AUTH_STARTED; 308 } catch (RemoteException e) { 309 Slog.e(TAG, "Remote exception", e); 310 } 311 } else { 312 // The UI was already showing :) 313 mState = STATE_AUTH_STARTED_UI_SHOWING; 314 } 315 } else { 316 Slog.v(TAG, "onCookieReceived: still waiting"); 317 } 318 } 319 isConfirmationRequired(BiometricSensor sensor)320 private boolean isConfirmationRequired(BiometricSensor sensor) { 321 return sensor.confirmationSupported() 322 && (sensor.confirmationAlwaysRequired(mUserId) 323 || mPreAuthInfo.confirmationRequested); 324 } 325 isConfirmationRequiredByAnyEligibleSensor()326 private boolean isConfirmationRequiredByAnyEligibleSensor() { 327 for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { 328 if (isConfirmationRequired(sensor)) { 329 return true; 330 } 331 } 332 return false; 333 } 334 startAllPreparedSensorsExceptFingerprint()335 private void startAllPreparedSensorsExceptFingerprint() { 336 startAllPreparedSensors(sensor -> sensor.modality != TYPE_FINGERPRINT); 337 } 338 startAllPreparedFingerprintSensors()339 private void startAllPreparedFingerprintSensors() { 340 startAllPreparedSensors(sensor -> sensor.modality == TYPE_FINGERPRINT); 341 } 342 startAllPreparedSensors(Function<BiometricSensor, Boolean> filter)343 private void startAllPreparedSensors(Function<BiometricSensor, Boolean> filter) { 344 for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { 345 if (filter.apply(sensor)) { 346 try { 347 if (DEBUG) { 348 Slog.v(TAG, "Starting sensor: " + sensor.id); 349 } 350 sensor.startSensor(); 351 } catch (RemoteException e) { 352 Slog.e(TAG, "Unable to start prepared client, sensor: " + sensor, e); 353 } 354 } 355 } 356 } 357 cancelAllSensors()358 private void cancelAllSensors() { 359 cancelAllSensors(sensor -> true); 360 } 361 cancelAllSensors(Function<BiometricSensor, Boolean> filter)362 private void cancelAllSensors(Function<BiometricSensor, Boolean> filter) { 363 // TODO: For multiple modalities, send a single ERROR_CANCELED only when all 364 // drivers have canceled authentication. We'd probably have to add a state for 365 // STATE_CANCELING for when we're waiting for final ERROR_CANCELED before 366 // sending the final error callback to the application. 367 for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { 368 try { 369 final boolean shouldCancel = filter.apply(sensor); 370 Slog.d(TAG, "sensorId: " + sensor.id + ", shouldCancel: " + shouldCancel); 371 if (shouldCancel) { 372 sensor.goToStateCancelling(mToken, mOpPackageName); 373 } 374 } catch (RemoteException e) { 375 Slog.e(TAG, "Unable to cancel authentication"); 376 } 377 } 378 } 379 380 /** 381 * @return true if this AuthSession is finished, e.g. should be set to null. 382 */ onErrorReceived(int sensorId, int cookie, @BiometricConstants.Errors int error, int vendorCode)383 boolean onErrorReceived(int sensorId, int cookie, @BiometricConstants.Errors int error, 384 int vendorCode) throws RemoteException { 385 Slog.d(TAG, "onErrorReceived sensor: " + sensorId + " error: " + error); 386 387 if (!containsCookie(cookie)) { 388 Slog.e(TAG, "Unknown/expired cookie: " + cookie); 389 return false; 390 } 391 392 // TODO: The sensor-specific state is not currently used, this would need to be updated if 393 // multiple authenticators are running. 394 for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { 395 if (sensor.getSensorState() == BiometricSensor.STATE_AUTHENTICATING) { 396 sensor.goToStoppedStateIfCookieMatches(cookie, error); 397 } 398 } 399 400 mErrorEscrow = error; 401 mVendorCodeEscrow = vendorCode; 402 403 final @BiometricAuthenticator.Modality int modality = sensorIdToModality(sensorId); 404 405 switch (mState) { 406 case STATE_AUTH_CALLED: { 407 // If any error is received while preparing the auth session (lockout, etc), 408 // and if device credential is allowed, just show the credential UI. 409 if (isAllowDeviceCredential()) { 410 @BiometricManager.Authenticators.Types int authenticators = 411 mPromptInfo.getAuthenticators(); 412 // Disallow biometric and notify SystemUI to show the authentication prompt. 413 authenticators = Utils.removeBiometricBits(authenticators); 414 mPromptInfo.setAuthenticators(authenticators); 415 416 mState = STATE_SHOWING_DEVICE_CREDENTIAL; 417 mMultiSensorMode = BIOMETRIC_MULTI_SENSOR_DEFAULT; 418 mMultiSensorState = MULTI_SENSOR_STATE_UNKNOWN; 419 mSensors = new int[0]; 420 421 mStatusBarService.showAuthenticationDialog( 422 mPromptInfo, 423 mSysuiReceiver, 424 mSensors /* sensorIds */, 425 true /* credentialAllowed */, 426 false /* requireConfirmation */, 427 mUserId, 428 mOpPackageName, 429 mOperationId, 430 mMultiSensorMode); 431 } else { 432 mClientReceiver.onError(modality, error, vendorCode); 433 return true; 434 } 435 break; 436 } 437 438 case STATE_AUTH_STARTED: 439 case STATE_AUTH_STARTED_UI_SHOWING: { 440 final boolean errorLockout = error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT 441 || error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT; 442 if (isAllowDeviceCredential() && errorLockout) { 443 // SystemUI handles transition from biometric to device credential. 444 mState = STATE_SHOWING_DEVICE_CREDENTIAL; 445 mStatusBarService.onBiometricError(modality, error, vendorCode); 446 } else if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) { 447 mStatusBarService.hideAuthenticationDialog(); 448 // TODO: If multiple authenticators are simultaneously running, this will 449 // need to be modified. Send the error to the client here, instead of doing 450 // a round trip to SystemUI. 451 mClientReceiver.onError(modality, error, vendorCode); 452 return true; 453 } else { 454 mState = STATE_ERROR_PENDING_SYSUI; 455 if (mMultiSensorMode == BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT 456 && mMultiSensorState == MULTI_SENSOR_STATE_FACE_SCANNING) { 457 // wait for the UI to signal when modality should switch 458 Slog.d(TAG, "onErrorReceived: waiting for modality switch callback"); 459 mMultiSensorState = MULTI_SENSOR_STATE_SWITCHING; 460 } 461 mStatusBarService.onBiometricError(modality, error, vendorCode); 462 } 463 break; 464 } 465 466 case STATE_AUTH_PAUSED: { 467 // In the "try again" state, we should forward canceled errors to 468 // the client and clean up. The only error we should get here is 469 // ERROR_CANCELED due to another client kicking us out. 470 mClientReceiver.onError(modality, error, vendorCode); 471 mStatusBarService.hideAuthenticationDialog(); 472 return true; 473 } 474 475 case STATE_SHOWING_DEVICE_CREDENTIAL: 476 Slog.d(TAG, "Biometric canceled, ignoring from state: " + mState); 477 break; 478 479 case STATE_CLIENT_DIED_CANCELLING: 480 mStatusBarService.hideAuthenticationDialog(); 481 return true; 482 483 default: 484 Slog.e(TAG, "Unhandled error state, mState: " + mState); 485 break; 486 } 487 488 return false; 489 } 490 onAcquired(int sensorId, int acquiredInfo, int vendorCode)491 void onAcquired(int sensorId, int acquiredInfo, int vendorCode) { 492 final String message = getAcquiredMessageForSensor(sensorId, acquiredInfo, vendorCode); 493 Slog.d(TAG, "sensorId: " + sensorId + " acquiredInfo: " + acquiredInfo 494 + " message: " + message); 495 if (message == null) { 496 return; 497 } 498 499 try { 500 mStatusBarService.onBiometricHelp(sensorIdToModality(sensorId), message); 501 } catch (RemoteException e) { 502 Slog.e(TAG, "Remote exception", e); 503 } 504 } 505 onSystemEvent(int event)506 void onSystemEvent(int event) { 507 if (!mPromptInfo.isReceiveSystemEvents()) { 508 return; 509 } 510 511 try { 512 mClientReceiver.onSystemEvent(event); 513 } catch (RemoteException e) { 514 Slog.e(TAG, "RemoteException", e); 515 } 516 } 517 onDialogAnimatedIn()518 void onDialogAnimatedIn() { 519 if (mState != STATE_AUTH_STARTED) { 520 Slog.w(TAG, "onDialogAnimatedIn, unexpected state: " + mState); 521 } 522 523 mState = STATE_AUTH_STARTED_UI_SHOWING; 524 525 if (mMultiSensorMode == BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT) { 526 mMultiSensorState = MULTI_SENSOR_STATE_FACE_SCANNING; 527 } else { 528 startFingerprintSensorsNow(); 529 } 530 } 531 532 // call anytime after onDialogAnimatedIn() to indicate it's appropriate to start the 533 // fingerprint sensor (i.e. face auth has failed or is not available) onStartFingerprint()534 void onStartFingerprint() { 535 if (mMultiSensorMode != BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT) { 536 Slog.e(TAG, "onStartFingerprint, unexpected mode: " + mMultiSensorMode); 537 return; 538 } 539 540 if (mState != STATE_AUTH_STARTED 541 && mState != STATE_AUTH_STARTED_UI_SHOWING 542 && mState != STATE_AUTH_PAUSED 543 && mState != STATE_ERROR_PENDING_SYSUI) { 544 Slog.w(TAG, "onStartFingerprint, started from unexpected state: " + mState); 545 } 546 547 mMultiSensorState = MULTI_SENSOR_STATE_FP_SCANNING; 548 startFingerprintSensorsNow(); 549 } 550 551 // unguarded helper for the above methods only startFingerprintSensorsNow()552 private void startFingerprintSensorsNow() { 553 startAllPreparedFingerprintSensors(); 554 mState = STATE_AUTH_STARTED_UI_SHOWING; 555 } 556 onTryAgainPressed()557 void onTryAgainPressed() { 558 if (mState != STATE_AUTH_PAUSED) { 559 Slog.w(TAG, "onTryAgainPressed, state: " + mState); 560 } 561 562 try { 563 setSensorsToStateWaitingForCookie(); 564 mState = STATE_AUTH_PAUSED_RESUMING; 565 } catch (RemoteException e) { 566 Slog.e(TAG, "RemoteException: " + e); 567 } 568 } 569 onAuthenticationSucceeded(int sensorId, boolean strong, byte[] token)570 void onAuthenticationSucceeded(int sensorId, boolean strong, 571 byte[] token) { 572 if (strong) { 573 mTokenEscrow = token; 574 } else { 575 if (token != null) { 576 Slog.w(TAG, "Dropping authToken for non-strong biometric, id: " + sensorId); 577 } 578 } 579 580 try { 581 // Notify SysUI that the biometric has been authenticated. SysUI already knows 582 // the implicit/explicit state and will react accordingly. 583 mStatusBarService.onBiometricAuthenticated(); 584 585 final boolean requireConfirmation = isConfirmationRequiredByAnyEligibleSensor(); 586 587 if (!requireConfirmation) { 588 mState = STATE_AUTHENTICATED_PENDING_SYSUI; 589 } else { 590 mAuthenticatedTimeMs = System.currentTimeMillis(); 591 mState = STATE_AUTH_PENDING_CONFIRM; 592 } 593 } catch (RemoteException e) { 594 Slog.e(TAG, "RemoteException", e); 595 } 596 } 597 onAuthenticationRejected()598 void onAuthenticationRejected() { 599 try { 600 mStatusBarService.onBiometricError(TYPE_NONE, 601 BiometricConstants.BIOMETRIC_PAUSED_REJECTED, 0 /* vendorCode */); 602 603 // TODO: This logic will need to be updated if BP is multi-modal 604 if (hasPausableBiometric()) { 605 // Pause authentication. onBiometricAuthenticated(false) causes the 606 // dialog to show a "try again" button for passive modalities. 607 mState = STATE_AUTH_PAUSED; 608 } 609 610 mClientReceiver.onAuthenticationFailed(); 611 } catch (RemoteException e) { 612 Slog.e(TAG, "RemoteException", e); 613 } 614 } 615 onAuthenticationTimedOut(int sensorId, int cookie, int error, int vendorCode)616 void onAuthenticationTimedOut(int sensorId, int cookie, int error, int vendorCode) { 617 try { 618 mStatusBarService.onBiometricError(sensorIdToModality(sensorId), error, vendorCode); 619 mState = STATE_AUTH_PAUSED; 620 } catch (RemoteException e) { 621 Slog.e(TAG, "RemoteException", e); 622 } 623 } 624 onDeviceCredentialPressed()625 void onDeviceCredentialPressed() { 626 // Cancel authentication. Skip the token/package check since we are cancelling 627 // from system server. The interface is permission protected so this is fine. 628 cancelAllSensors(); 629 mState = STATE_SHOWING_DEVICE_CREDENTIAL; 630 } 631 632 /** 633 * @return true if this session is finished and should be set to null. 634 */ onClientDied()635 boolean onClientDied() { 636 try { 637 switch (mState) { 638 case STATE_AUTH_STARTED: 639 case STATE_AUTH_STARTED_UI_SHOWING: 640 mState = STATE_CLIENT_DIED_CANCELLING; 641 cancelAllSensors(); 642 return false; 643 default: 644 mStatusBarService.hideAuthenticationDialog(); 645 return true; 646 } 647 } catch (RemoteException e) { 648 Slog.e(TAG, "Remote Exception: " + e); 649 return true; 650 } 651 } 652 logOnDialogDismissed(@iometricPrompt.DismissedReason int reason)653 private void logOnDialogDismissed(@BiometricPrompt.DismissedReason int reason) { 654 if (reason == BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED) { 655 // Explicit auth, authentication confirmed. 656 // Latency in this case is authenticated -> confirmed. <Biometric>Service 657 // should have the first half (first acquired -> authenticated). 658 final long latency = System.currentTimeMillis() - mAuthenticatedTimeMs; 659 660 if (DEBUG) { 661 Slog.v(TAG, "Confirmed! Modality: " + statsModality() 662 + ", User: " + mUserId 663 + ", IsCrypto: " + isCrypto() 664 + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT 665 + ", RequireConfirmation: " + mPreAuthInfo.confirmationRequested 666 + ", State: " + FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED 667 + ", Latency: " + latency); 668 } 669 670 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED, 671 statsModality(), 672 mUserId, 673 isCrypto(), 674 BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, 675 mPreAuthInfo.confirmationRequested, 676 FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED, 677 latency, 678 mDebugEnabled, 679 -1 /* sensorId */, 680 -1f /* ambientLightLux */); 681 } else { 682 final long latency = System.currentTimeMillis() - mStartTimeMs; 683 684 int error = reason == BiometricPrompt.DISMISSED_REASON_NEGATIVE 685 ? BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON 686 : reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL 687 ? BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED 688 : 0; 689 if (DEBUG) { 690 Slog.v(TAG, "Dismissed! Modality: " + statsModality() 691 + ", User: " + mUserId 692 + ", IsCrypto: " + isCrypto() 693 + ", Action: " + BiometricsProtoEnums.ACTION_AUTHENTICATE 694 + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT 695 + ", Reason: " + reason 696 + ", Error: " + error 697 + ", Latency: " + latency); 698 } 699 // Auth canceled 700 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED, 701 statsModality(), 702 mUserId, 703 isCrypto(), 704 BiometricsProtoEnums.ACTION_AUTHENTICATE, 705 BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, 706 error, 707 0 /* vendorCode */, 708 mDebugEnabled, 709 latency, 710 -1 /* sensorId */); 711 } 712 } 713 onDialogDismissed(@iometricPrompt.DismissedReason int reason, @Nullable byte[] credentialAttestation)714 void onDialogDismissed(@BiometricPrompt.DismissedReason int reason, 715 @Nullable byte[] credentialAttestation) { 716 logOnDialogDismissed(reason); 717 try { 718 switch (reason) { 719 case BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED: 720 if (credentialAttestation != null) { 721 mKeyStore.addAuthToken(credentialAttestation); 722 } else { 723 Slog.e(TAG, "credentialAttestation is null"); 724 } 725 case BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED: 726 case BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED: 727 if (mTokenEscrow != null) { 728 final int result = mKeyStore.addAuthToken(mTokenEscrow); 729 Slog.d(TAG, "addAuthToken: " + result); 730 } else { 731 Slog.e(TAG, "mTokenEscrow is null"); 732 } 733 mClientReceiver.onAuthenticationSucceeded( 734 Utils.getAuthenticationTypeForResult(reason)); 735 break; 736 737 case BiometricPrompt.DISMISSED_REASON_NEGATIVE: 738 mClientReceiver.onDialogDismissed(reason); 739 break; 740 741 case BiometricPrompt.DISMISSED_REASON_USER_CANCEL: 742 mClientReceiver.onError( 743 getEligibleModalities(), 744 BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED, 745 0 /* vendorCode */ 746 ); 747 break; 748 749 case BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED: 750 case BiometricPrompt.DISMISSED_REASON_ERROR: 751 mClientReceiver.onError( 752 getEligibleModalities(), 753 mErrorEscrow, 754 mVendorCodeEscrow 755 ); 756 break; 757 758 default: 759 Slog.w(TAG, "Unhandled reason: " + reason); 760 break; 761 } 762 } catch (RemoteException e) { 763 Slog.e(TAG, "Remote exception", e); 764 } finally { 765 // ensure everything is cleaned up when dismissed 766 cancelAllSensors(); 767 } 768 } 769 770 /** 771 * Cancels authentication for the entire authentication session. The caller will receive 772 * {@link BiometricPrompt#BIOMETRIC_ERROR_CANCELED} at some point. 773 * 774 * @param force if true, will immediately dismiss the dialog and send onError to the client 775 * @return true if this AuthSession is finished, e.g. should be set to null 776 */ onCancelAuthSession(boolean force)777 boolean onCancelAuthSession(boolean force) { 778 final boolean authStarted = mState == STATE_AUTH_CALLED 779 || mState == STATE_AUTH_STARTED 780 || mState == STATE_AUTH_STARTED_UI_SHOWING; 781 782 cancelAllSensors(); 783 if (authStarted && !force) { 784 // Wait for ERROR_CANCELED to be returned from the sensors 785 return false; 786 } else { 787 // If we're in a state where biometric sensors are not running (e.g. pending confirm, 788 // showing device credential, etc), we need to dismiss the dialog and send our own 789 // ERROR_CANCELED to the client, since we won't be getting an onError from the driver. 790 try { 791 // Send error to client 792 mClientReceiver.onError( 793 getEligibleModalities(), 794 BiometricConstants.BIOMETRIC_ERROR_CANCELED, 795 0 /* vendorCode */ 796 ); 797 mStatusBarService.hideAuthenticationDialog(); 798 return true; 799 } catch (RemoteException e) { 800 Slog.e(TAG, "Remote exception", e); 801 } 802 } 803 return false; 804 } 805 isCrypto()806 boolean isCrypto() { 807 return mOperationId != 0; 808 } 809 containsCookie(int cookie)810 private boolean containsCookie(int cookie) { 811 for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { 812 if (sensor.getCookie() == cookie) { 813 return true; 814 } 815 } 816 return false; 817 } 818 isAllowDeviceCredential()819 private boolean isAllowDeviceCredential() { 820 return Utils.isCredentialRequested(mPromptInfo); 821 } 822 allCookiesReceived()823 boolean allCookiesReceived() { 824 final int remainingCookies = mPreAuthInfo.numSensorsWaitingForCookie(); 825 Slog.d(TAG, "Remaining cookies: " + remainingCookies); 826 return remainingCookies == 0; 827 } 828 hasPausableBiometric()829 private boolean hasPausableBiometric() { 830 for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { 831 if (sensor.modality == TYPE_FACE) { 832 return true; 833 } 834 } 835 return false; 836 } 837 getState()838 @SessionState int getState() { 839 return mState; 840 } 841 statsModality()842 private int statsModality() { 843 int modality = 0; 844 845 for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { 846 if ((sensor.modality & BiometricAuthenticator.TYPE_FINGERPRINT) != 0) { 847 modality |= BiometricsProtoEnums.MODALITY_FINGERPRINT; 848 } 849 if ((sensor.modality & BiometricAuthenticator.TYPE_IRIS) != 0) { 850 modality |= BiometricsProtoEnums.MODALITY_IRIS; 851 } 852 if ((sensor.modality & BiometricAuthenticator.TYPE_FACE) != 0) { 853 modality |= BiometricsProtoEnums.MODALITY_FACE; 854 } 855 } 856 857 return modality; 858 } 859 sensorIdToModality(int sensorId)860 private @Modality int sensorIdToModality(int sensorId) { 861 for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { 862 if (sensorId == sensor.id) { 863 return sensor.modality; 864 } 865 } 866 Slog.e(TAG, "Unknown sensor: " + sensorId); 867 return TYPE_NONE; 868 } 869 getAcquiredMessageForSensor(int sensorId, int acquiredInfo, int vendorCode)870 private String getAcquiredMessageForSensor(int sensorId, int acquiredInfo, int vendorCode) { 871 final @Modality int modality = sensorIdToModality(sensorId); 872 switch (modality) { 873 case BiometricAuthenticator.TYPE_FINGERPRINT: 874 return FingerprintManager.getAcquiredString(mContext, acquiredInfo, vendorCode); 875 case BiometricAuthenticator.TYPE_FACE: 876 return FaceManager.getAuthHelpMessage(mContext, acquiredInfo, vendorCode); 877 default: 878 return null; 879 } 880 } 881 882 @BiometricMultiSensorMode getMultiSensorModeForNewSession(Collection<BiometricSensor> sensors)883 private static int getMultiSensorModeForNewSession(Collection<BiometricSensor> sensors) { 884 boolean hasFace = false; 885 boolean hasFingerprint = false; 886 887 for (BiometricSensor sensor: sensors) { 888 if (sensor.modality == TYPE_FACE) { 889 hasFace = true; 890 } else if (sensor.modality == TYPE_FINGERPRINT) { 891 hasFingerprint = true; 892 } 893 } 894 895 if (hasFace && hasFingerprint) { 896 return BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT; 897 } 898 return BIOMETRIC_MULTI_SENSOR_DEFAULT; 899 } 900 901 @Override toString()902 public String toString() { 903 return "State: " + mState 904 + ", isCrypto: " + isCrypto() 905 + ", PreAuthInfo: " + mPreAuthInfo; 906 } 907 } 908