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