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