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