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