1 /* 2 * Copyright (C) 2018 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.Manifest.permission.USE_BIOMETRIC; 20 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; 21 import static android.Manifest.permission.USE_FINGERPRINT; 22 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; 23 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; 24 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS; 25 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE; 26 27 import android.app.ActivityManager; 28 import android.app.ActivityTaskManager; 29 import android.app.AppOpsManager; 30 import android.app.IActivityTaskManager; 31 import android.app.KeyguardManager; 32 import android.app.TaskStackListener; 33 import android.app.UserSwitchObserver; 34 import android.content.ContentResolver; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.content.pm.PackageManager; 38 import android.database.ContentObserver; 39 import android.hardware.biometrics.BiometricAuthenticator; 40 import android.hardware.biometrics.BiometricConstants; 41 import android.hardware.biometrics.BiometricPrompt; 42 import android.hardware.biometrics.BiometricSourceType; 43 import android.hardware.biometrics.BiometricsProtoEnums; 44 import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback; 45 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; 46 import android.hardware.biometrics.IBiometricService; 47 import android.hardware.biometrics.IBiometricServiceReceiver; 48 import android.hardware.biometrics.IBiometricServiceReceiverInternal; 49 import android.hardware.face.FaceManager; 50 import android.hardware.face.IFaceService; 51 import android.hardware.fingerprint.FingerprintManager; 52 import android.hardware.fingerprint.IFingerprintService; 53 import android.net.Uri; 54 import android.os.Binder; 55 import android.os.Bundle; 56 import android.os.DeadObjectException; 57 import android.os.Handler; 58 import android.os.IBinder; 59 import android.os.Looper; 60 import android.os.Message; 61 import android.os.RemoteException; 62 import android.os.ServiceManager; 63 import android.os.UserHandle; 64 import android.provider.Settings; 65 import android.security.KeyStore; 66 import android.text.TextUtils; 67 import android.util.Pair; 68 import android.util.Slog; 69 import android.util.StatsLog; 70 71 import com.android.internal.R; 72 import com.android.internal.os.SomeArgs; 73 import com.android.internal.statusbar.IStatusBarService; 74 import com.android.server.SystemService; 75 76 import java.util.ArrayList; 77 import java.util.HashMap; 78 import java.util.Iterator; 79 import java.util.List; 80 import java.util.Map; 81 import java.util.Random; 82 83 /** 84 * System service that arbitrates the modality for BiometricPrompt to use. 85 */ 86 public class BiometricService extends SystemService { 87 88 private static final String TAG = "BiometricService"; 89 private static final boolean DEBUG = true; 90 91 private static final int MSG_ON_TASK_STACK_CHANGED = 1; 92 private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2; 93 private static final int MSG_ON_AUTHENTICATION_FAILED = 3; 94 private static final int MSG_ON_ERROR = 4; 95 private static final int MSG_ON_ACQUIRED = 5; 96 private static final int MSG_ON_DISMISSED = 6; 97 private static final int MSG_ON_TRY_AGAIN_PRESSED = 7; 98 private static final int MSG_ON_READY_FOR_AUTHENTICATION = 8; 99 private static final int MSG_AUTHENTICATE = 9; 100 private static final int MSG_CANCEL_AUTHENTICATION = 10; 101 private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS = 11; 102 private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR = 12; 103 private static final int MSG_REGISTER_CANCELLATION_CALLBACK = 13; 104 105 private static final int[] FEATURE_ID = { 106 TYPE_FINGERPRINT, 107 TYPE_IRIS, 108 TYPE_FACE 109 }; 110 111 /** 112 * Authentication either just called and we have not transitioned to the CALLED state, or 113 * authentication terminated (success or error). 114 */ 115 private static final int STATE_AUTH_IDLE = 0; 116 /** 117 * Authentication was called and we are waiting for the <Biometric>Services to return their 118 * cookies before starting the hardware and showing the BiometricPrompt. 119 */ 120 private static final int STATE_AUTH_CALLED = 1; 121 /** 122 * Authentication started, BiometricPrompt is showing and the hardware is authenticating. 123 */ 124 private static final int STATE_AUTH_STARTED = 2; 125 /** 126 * Authentication is paused, waiting for the user to press "try again" button. Only 127 * passive modalities such as Face or Iris should have this state. Note that for passive 128 * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from 129 * fingerprint. 130 */ 131 private static final int STATE_AUTH_PAUSED = 3; 132 /** 133 * Authentication is successful, but we're waiting for the user to press "confirm" button. 134 */ 135 private static final int STATE_AUTH_PENDING_CONFIRM = 5; 136 /** 137 * Biometric authentication was canceled, but the device is now showing ConfirmDeviceCredential 138 */ 139 private static final int STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC = 6; 140 141 private final class AuthSession implements IBinder.DeathRecipient { 142 // Map of Authenticator/Cookie pairs. We expect to receive the cookies back from 143 // <Biometric>Services before we can start authenticating. Pairs that have been returned 144 // are moved to mModalitiesMatched. 145 final HashMap<Integer, Integer> mModalitiesWaiting; 146 // Pairs that have been matched. 147 final HashMap<Integer, Integer> mModalitiesMatched = new HashMap<>(); 148 149 // The following variables are passed to authenticateInternal, which initiates the 150 // appropriate <Biometric>Services. 151 final IBinder mToken; 152 final long mSessionId; 153 final int mUserId; 154 // Original receiver from BiometricPrompt. 155 final IBiometricServiceReceiver mClientReceiver; 156 final String mOpPackageName; 157 // Info to be shown on BiometricDialog when all cookies are returned. 158 final Bundle mBundle; 159 final int mCallingUid; 160 final int mCallingPid; 161 final int mCallingUserId; 162 // Continue authentication with the same modality/modalities after "try again" is 163 // pressed 164 final int mModality; 165 final boolean mRequireConfirmation; 166 167 // The current state, which can be either idle, called, or started 168 private int mState = STATE_AUTH_IDLE; 169 // For explicit confirmation, do not send to keystore until the user has confirmed 170 // the authentication. 171 byte[] mTokenEscrow; 172 173 // Timestamp when authentication started 174 private long mStartTimeMs; 175 // Timestamp when hardware authentication occurred 176 private long mAuthenticatedTimeMs; 177 178 // TODO(b/123378871): Remove when moved. 179 private IBiometricConfirmDeviceCredentialCallback mConfirmDeviceCredentialCallback; 180 AuthSession(HashMap<Integer, Integer> modalities, IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, int callingUid, int callingPid, int callingUserId, int modality, boolean requireConfirmation, IBiometricConfirmDeviceCredentialCallback callback)181 AuthSession(HashMap<Integer, Integer> modalities, IBinder token, long sessionId, 182 int userId, IBiometricServiceReceiver receiver, String opPackageName, 183 Bundle bundle, int callingUid, int callingPid, int callingUserId, 184 int modality, boolean requireConfirmation, 185 IBiometricConfirmDeviceCredentialCallback callback) { 186 mModalitiesWaiting = modalities; 187 mToken = token; 188 mSessionId = sessionId; 189 mUserId = userId; 190 mClientReceiver = receiver; 191 mOpPackageName = opPackageName; 192 mBundle = bundle; 193 mCallingUid = callingUid; 194 mCallingPid = callingPid; 195 mCallingUserId = callingUserId; 196 mModality = modality; 197 mRequireConfirmation = requireConfirmation; 198 mConfirmDeviceCredentialCallback = callback; 199 200 if (isFromConfirmDeviceCredential()) { 201 try { 202 token.linkToDeath(this, 0 /* flags */); 203 } catch (RemoteException e) { 204 Slog.e(TAG, "Unable to link to death", e); 205 } 206 } 207 } 208 isCrypto()209 boolean isCrypto() { 210 return mSessionId != 0; 211 } 212 isFromConfirmDeviceCredential()213 boolean isFromConfirmDeviceCredential() { 214 return mBundle.getBoolean(BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false); 215 } 216 containsCookie(int cookie)217 boolean containsCookie(int cookie) { 218 if (mModalitiesWaiting != null && mModalitiesWaiting.containsValue(cookie)) { 219 return true; 220 } 221 if (mModalitiesMatched != null && mModalitiesMatched.containsValue(cookie)) { 222 return true; 223 } 224 return false; 225 } 226 227 // TODO(b/123378871): Remove when moved. 228 @Override binderDied()229 public void binderDied() { 230 mHandler.post(() -> { 231 Slog.e(TAG, "Binder died, killing ConfirmDeviceCredential"); 232 if (mConfirmDeviceCredentialCallback == null) { 233 Slog.e(TAG, "Callback is null"); 234 return; 235 } 236 237 try { 238 mConfirmDeviceCredentialCallback.cancel(); 239 mConfirmDeviceCredentialCallback = null; 240 } catch (RemoteException e) { 241 Slog.e(TAG, "Unable to send cancel", e); 242 } 243 }); 244 } 245 } 246 247 private final class BiometricTaskStackListener extends TaskStackListener { 248 @Override onTaskStackChanged()249 public void onTaskStackChanged() { 250 mHandler.sendEmptyMessage(MSG_ON_TASK_STACK_CHANGED); 251 } 252 } 253 254 private final AppOpsManager mAppOps; 255 private final boolean mHasFeatureFingerprint; 256 private final boolean mHasFeatureIris; 257 private final boolean mHasFeatureFace; 258 private final SettingObserver mSettingObserver; 259 private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks; 260 private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener(); 261 private final Random mRandom = new Random(); 262 263 private IFingerprintService mFingerprintService; 264 private IFaceService mFaceService; 265 private IActivityTaskManager mActivityTaskManager; 266 private IStatusBarService mStatusBarService; 267 268 // Get and cache the available authenticator (manager) classes. Used since aidl doesn't support 269 // polymorphism :/ 270 final ArrayList<Authenticator> mAuthenticators = new ArrayList<>(); 271 272 // Cache the current service that's being used. This is the service which 273 // cancelAuthentication() must be forwarded to. This is just a cache, and the actual 274 // check (is caller the current client) is done in the <Biometric>Service. 275 // Since Settings/System (not application) is responsible for changing preference, this 276 // should be safe. 277 private int mCurrentModality; 278 279 // The current authentication session, null if idle/done. We need to track both the current 280 // and pending sessions since errors may be sent to either. 281 private AuthSession mCurrentAuthSession; 282 private AuthSession mPendingAuthSession; 283 284 // TODO(b/123378871): Remove when moved. 285 // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the 286 // client (app) receiver. BiometricService internally launches CDCA which invokes 287 // BiometricService to start authentication (normal path). When auth is success/rejected, 288 // CDCA will use an aidl method to poke BiometricService - the result will then be forwarded 289 // to this receiver. 290 private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver; 291 292 private final Handler mHandler = new Handler(Looper.getMainLooper()) { 293 @Override 294 public void handleMessage(Message msg) { 295 switch (msg.what) { 296 case MSG_ON_TASK_STACK_CHANGED: { 297 handleTaskStackChanged(); 298 break; 299 } 300 301 case MSG_ON_AUTHENTICATION_SUCCEEDED: { 302 SomeArgs args = (SomeArgs) msg.obj; 303 handleAuthenticationSucceeded( 304 (boolean) args.arg1 /* requireConfirmation */, 305 (byte[]) args.arg2 /* token */); 306 args.recycle(); 307 break; 308 } 309 310 case MSG_ON_AUTHENTICATION_FAILED: { 311 handleAuthenticationFailed((String) msg.obj /* failureReason */); 312 break; 313 } 314 315 case MSG_ON_ERROR: { 316 SomeArgs args = (SomeArgs) msg.obj; 317 handleOnError( 318 args.argi1 /* cookie */, 319 args.argi2 /* error */, 320 (String) args.arg1 /* message */); 321 args.recycle(); 322 break; 323 } 324 325 case MSG_ON_ACQUIRED: { 326 SomeArgs args = (SomeArgs) msg.obj; 327 handleOnAcquired( 328 args.argi1 /* acquiredInfo */, 329 (String) args.arg1 /* message */); 330 args.recycle(); 331 break; 332 } 333 334 case MSG_ON_DISMISSED: { 335 handleOnDismissed(msg.arg1); 336 break; 337 } 338 339 case MSG_ON_TRY_AGAIN_PRESSED: { 340 handleOnTryAgainPressed(); 341 break; 342 } 343 344 case MSG_ON_READY_FOR_AUTHENTICATION: { 345 SomeArgs args = (SomeArgs) msg.obj; 346 handleOnReadyForAuthentication( 347 args.argi1 /* cookie */, 348 (boolean) args.arg1 /* requireConfirmation */, 349 args.argi2 /* userId */); 350 args.recycle(); 351 break; 352 } 353 354 case MSG_AUTHENTICATE: { 355 SomeArgs args = (SomeArgs) msg.obj; 356 handleAuthenticate( 357 (IBinder) args.arg1 /* token */, 358 (long) args.arg2 /* sessionId */, 359 args.argi1 /* userid */, 360 (IBiometricServiceReceiver) args.arg3 /* receiver */, 361 (String) args.arg4 /* opPackageName */, 362 (Bundle) args.arg5 /* bundle */, 363 args.argi2 /* callingUid */, 364 args.argi3 /* callingPid */, 365 args.argi4 /* callingUserId */, 366 (IBiometricConfirmDeviceCredentialCallback) args.arg6 /* callback */); 367 args.recycle(); 368 break; 369 } 370 371 case MSG_CANCEL_AUTHENTICATION: { 372 SomeArgs args = (SomeArgs) msg.obj; 373 handleCancelAuthentication( 374 (IBinder) args.arg1 /* token */, 375 (String) args.arg2 /* opPackageName */); 376 args.recycle(); 377 break; 378 } 379 380 case MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS: { 381 handleOnConfirmDeviceCredentialSuccess(); 382 break; 383 } 384 385 case MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR: { 386 SomeArgs args = (SomeArgs) msg.obj; 387 handleOnConfirmDeviceCredentialError( 388 args.argi1 /* error */, 389 (String) args.arg1 /* errorMsg */); 390 args.recycle(); 391 break; 392 } 393 394 case MSG_REGISTER_CANCELLATION_CALLBACK: { 395 handleRegisterCancellationCallback( 396 (IBiometricConfirmDeviceCredentialCallback) msg.obj /* callback */); 397 break; 398 } 399 400 default: 401 Slog.e(TAG, "Unknown message: " + msg); 402 break; 403 } 404 } 405 }; 406 407 private final class Authenticator { 408 int mType; 409 BiometricAuthenticator mAuthenticator; 410 Authenticator(int type, BiometricAuthenticator authenticator)411 Authenticator(int type, BiometricAuthenticator authenticator) { 412 mType = type; 413 mAuthenticator = authenticator; 414 } 415 getType()416 int getType() { 417 return mType; 418 } 419 getAuthenticator()420 BiometricAuthenticator getAuthenticator() { 421 return mAuthenticator; 422 } 423 } 424 425 private final class SettingObserver extends ContentObserver { 426 427 private static final boolean DEFAULT_KEYGUARD_ENABLED = true; 428 private static final boolean DEFAULT_APP_ENABLED = true; 429 private static final boolean DEFAULT_ALWAYS_REQUIRE_CONFIRMATION = false; 430 431 private final Uri FACE_UNLOCK_KEYGUARD_ENABLED = 432 Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED); 433 private final Uri FACE_UNLOCK_APP_ENABLED = 434 Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_APP_ENABLED); 435 private final Uri FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION = 436 Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION); 437 438 private final ContentResolver mContentResolver; 439 440 private Map<Integer, Boolean> mFaceEnabledOnKeyguard = new HashMap<>(); 441 private Map<Integer, Boolean> mFaceEnabledForApps = new HashMap<>(); 442 private Map<Integer, Boolean> mFaceAlwaysRequireConfirmation = new HashMap<>(); 443 444 /** 445 * Creates a content observer. 446 * 447 * @param handler The handler to run {@link #onChange} on, or null if none. 448 */ SettingObserver(Handler handler)449 SettingObserver(Handler handler) { 450 super(handler); 451 mContentResolver = getContext().getContentResolver(); 452 updateContentObserver(); 453 } 454 updateContentObserver()455 void updateContentObserver() { 456 mContentResolver.unregisterContentObserver(this); 457 mContentResolver.registerContentObserver(FACE_UNLOCK_KEYGUARD_ENABLED, 458 false /* notifyForDescendents */, 459 this /* observer */, 460 UserHandle.USER_ALL); 461 mContentResolver.registerContentObserver(FACE_UNLOCK_APP_ENABLED, 462 false /* notifyForDescendents */, 463 this /* observer */, 464 UserHandle.USER_ALL); 465 mContentResolver.registerContentObserver(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, 466 false /* notifyForDescendents */, 467 this /* observer */, 468 UserHandle.USER_ALL); 469 } 470 471 @Override onChange(boolean selfChange, Uri uri, int userId)472 public void onChange(boolean selfChange, Uri uri, int userId) { 473 if (FACE_UNLOCK_KEYGUARD_ENABLED.equals(uri)) { 474 mFaceEnabledOnKeyguard.put(userId, Settings.Secure.getIntForUser( 475 mContentResolver, 476 Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED, 477 DEFAULT_KEYGUARD_ENABLED ? 1 : 0 /* default */, 478 userId) != 0); 479 480 if (userId == ActivityManager.getCurrentUser() && !selfChange) { 481 notifyEnabledOnKeyguardCallbacks(userId); 482 } 483 } else if (FACE_UNLOCK_APP_ENABLED.equals(uri)) { 484 mFaceEnabledForApps.put(userId, Settings.Secure.getIntForUser( 485 mContentResolver, 486 Settings.Secure.FACE_UNLOCK_APP_ENABLED, 487 DEFAULT_APP_ENABLED ? 1 : 0 /* default */, 488 userId) != 0); 489 } else if (FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION.equals(uri)) { 490 mFaceAlwaysRequireConfirmation.put(userId, Settings.Secure.getIntForUser( 491 mContentResolver, 492 Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, 493 DEFAULT_ALWAYS_REQUIRE_CONFIRMATION ? 1 : 0 /* default */, 494 userId) != 0); 495 } 496 } 497 getFaceEnabledOnKeyguard()498 boolean getFaceEnabledOnKeyguard() { 499 final int user = ActivityManager.getCurrentUser(); 500 if (!mFaceEnabledOnKeyguard.containsKey(user)) { 501 onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED, user); 502 } 503 return mFaceEnabledOnKeyguard.get(user); 504 } 505 getFaceEnabledForApps(int userId)506 boolean getFaceEnabledForApps(int userId) { 507 if (!mFaceEnabledForApps.containsKey(userId)) { 508 onChange(true /* selfChange */, FACE_UNLOCK_APP_ENABLED, userId); 509 } 510 return mFaceEnabledForApps.getOrDefault(userId, DEFAULT_APP_ENABLED); 511 } 512 getFaceAlwaysRequireConfirmation(int userId)513 boolean getFaceAlwaysRequireConfirmation(int userId) { 514 if (!mFaceAlwaysRequireConfirmation.containsKey(userId)) { 515 onChange(true /* selfChange */, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, userId); 516 } 517 return mFaceAlwaysRequireConfirmation.get(userId); 518 } 519 notifyEnabledOnKeyguardCallbacks(int userId)520 void notifyEnabledOnKeyguardCallbacks(int userId) { 521 List<EnabledOnKeyguardCallback> callbacks = mEnabledOnKeyguardCallbacks; 522 for (int i = 0; i < callbacks.size(); i++) { 523 callbacks.get(i).notify(BiometricSourceType.FACE, 524 mFaceEnabledOnKeyguard.getOrDefault(userId, DEFAULT_KEYGUARD_ENABLED), 525 userId); 526 } 527 } 528 } 529 530 private final class EnabledOnKeyguardCallback implements IBinder.DeathRecipient { 531 532 private final IBiometricEnabledOnKeyguardCallback mCallback; 533 EnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback)534 EnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback) { 535 mCallback = callback; 536 try { 537 mCallback.asBinder().linkToDeath(EnabledOnKeyguardCallback.this, 0); 538 } catch (RemoteException e) { 539 Slog.w(TAG, "Unable to linkToDeath", e); 540 } 541 } 542 notify(BiometricSourceType sourceType, boolean enabled, int userId)543 void notify(BiometricSourceType sourceType, boolean enabled, int userId) { 544 try { 545 mCallback.onChanged(sourceType, enabled, userId); 546 } catch (DeadObjectException e) { 547 Slog.w(TAG, "Death while invoking notify", e); 548 mEnabledOnKeyguardCallbacks.remove(this); 549 } catch (RemoteException e) { 550 Slog.w(TAG, "Failed to invoke onChanged", e); 551 } 552 } 553 554 @Override binderDied()555 public void binderDied() { 556 Slog.e(TAG, "Enabled callback binder died"); 557 mEnabledOnKeyguardCallbacks.remove(this); 558 } 559 } 560 561 // Wrap the client's receiver so we can do things with the BiometricDialog first 562 private final IBiometricServiceReceiverInternal mInternalReceiver = 563 new IBiometricServiceReceiverInternal.Stub() { 564 @Override 565 public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token) 566 throws RemoteException { 567 SomeArgs args = SomeArgs.obtain(); 568 args.arg1 = requireConfirmation; 569 args.arg2 = token; 570 mHandler.obtainMessage(MSG_ON_AUTHENTICATION_SUCCEEDED, args).sendToTarget(); 571 } 572 573 @Override 574 public void onAuthenticationFailed(int cookie, boolean requireConfirmation) 575 throws RemoteException { 576 String failureReason = getContext().getString(R.string.biometric_not_recognized); 577 mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, failureReason).sendToTarget(); 578 } 579 580 @Override 581 public void onError(int cookie, int error, String message) throws RemoteException { 582 // Determine if error is hard or soft error. Certain errors (such as TIMEOUT) are 583 // soft errors and we should allow the user to try authenticating again instead of 584 // dismissing BiometricPrompt. 585 if (error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT) { 586 mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, message).sendToTarget(); 587 } else { 588 SomeArgs args = SomeArgs.obtain(); 589 args.argi1 = cookie; 590 args.argi2 = error; 591 args.arg1 = message; 592 mHandler.obtainMessage(MSG_ON_ERROR, args).sendToTarget(); 593 } 594 } 595 596 @Override 597 public void onAcquired(int acquiredInfo, String message) throws RemoteException { 598 SomeArgs args = SomeArgs.obtain(); 599 args.argi1 = acquiredInfo; 600 args.arg1 = message; 601 mHandler.obtainMessage(MSG_ON_ACQUIRED, args).sendToTarget(); 602 } 603 604 @Override 605 public void onDialogDismissed(int reason) throws RemoteException { 606 mHandler.obtainMessage(MSG_ON_DISMISSED, reason, 0 /* arg2 */).sendToTarget(); 607 } 608 609 @Override 610 public void onTryAgainPressed() { 611 mHandler.sendEmptyMessage(MSG_ON_TRY_AGAIN_PRESSED); 612 } 613 }; 614 615 616 /** 617 * This is just a pass-through service that wraps Fingerprint, Iris, Face services. This service 618 * should not carry any state. The reality is we need to keep a tiny amount of state so that 619 * cancelAuthentication() can go to the right place. 620 */ 621 private final class BiometricServiceWrapper extends IBiometricService.Stub { 622 @Override // Binder call onReadyForAuthentication(int cookie, boolean requireConfirmation, int userId)623 public void onReadyForAuthentication(int cookie, boolean requireConfirmation, int userId) { 624 checkInternalPermission(); 625 626 SomeArgs args = SomeArgs.obtain(); 627 args.argi1 = cookie; 628 args.arg1 = requireConfirmation; 629 args.argi2 = userId; 630 mHandler.obtainMessage(MSG_ON_READY_FOR_AUTHENTICATION, args).sendToTarget(); 631 } 632 633 @Override // Binder call authenticate(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, IBiometricConfirmDeviceCredentialCallback callback)634 public void authenticate(IBinder token, long sessionId, int userId, 635 IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, 636 IBiometricConfirmDeviceCredentialCallback callback) 637 throws RemoteException { 638 final int callingUid = Binder.getCallingUid(); 639 final int callingPid = Binder.getCallingPid(); 640 final int callingUserId = UserHandle.getCallingUserId(); 641 642 // TODO(b/123378871): Remove when moved. 643 if (callback != null) { 644 checkInternalPermission(); 645 } 646 647 // In the BiometricServiceBase, check do the AppOps and foreground check. 648 if (userId == callingUserId) { 649 // Check the USE_BIOMETRIC permission here. 650 checkPermission(); 651 } else { 652 // Only allow internal clients to authenticate with a different userId 653 Slog.w(TAG, "User " + callingUserId + " is requesting authentication of userid: " 654 + userId); 655 checkInternalPermission(); 656 } 657 658 if (token == null || receiver == null || opPackageName == null || bundle == null) { 659 Slog.e(TAG, "Unable to authenticate, one or more null arguments"); 660 return; 661 } 662 663 final boolean isFromConfirmDeviceCredential = 664 bundle.getBoolean(BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false); 665 if (isFromConfirmDeviceCredential) { 666 checkInternalPermission(); 667 } 668 669 // Check the usage of this in system server. Need to remove this check if it becomes 670 // a public API. 671 final boolean useDefaultTitle = 672 bundle.getBoolean(BiometricPrompt.KEY_USE_DEFAULT_TITLE, false); 673 if (useDefaultTitle) { 674 checkInternalPermission(); 675 // Set the default title if necessary 676 if (TextUtils.isEmpty(bundle.getCharSequence(BiometricPrompt.KEY_TITLE))) { 677 bundle.putCharSequence(BiometricPrompt.KEY_TITLE, 678 getContext().getString(R.string.biometric_dialog_default_title)); 679 } 680 } 681 682 // Launch CDC instead if necessary. CDC will return results through an AIDL call, since 683 // we can't get activity results. Store the receiver somewhere so we can forward the 684 // result back to the client. 685 // TODO(b/123378871): Remove when moved. 686 if (bundle.getBoolean(BiometricPrompt.KEY_ALLOW_DEVICE_CREDENTIAL)) { 687 mHandler.post(() -> { 688 final KeyguardManager kgm = getContext().getSystemService( 689 KeyguardManager.class); 690 if (!kgm.isDeviceSecure()) { 691 try { 692 receiver.onError( 693 BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL, 694 getContext().getString( 695 R.string.biometric_error_device_not_secured)); 696 } catch (RemoteException e) { 697 Slog.e(TAG, "Remote exception", e); 698 } 699 return; 700 } 701 mConfirmDeviceCredentialReceiver = receiver; 702 // Use this so we don't need to duplicate logic.. 703 final Intent intent = kgm.createConfirmDeviceCredentialIntent(null /* title */, 704 null /* description */, userId); 705 // Then give it the bundle to do magic behavior.. 706 intent.putExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE, bundle); 707 // Create a new task with this activity located at the root. 708 intent.setFlags( 709 Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT); 710 getContext().startActivityAsUser(intent, UserHandle.CURRENT); 711 }); 712 return; 713 } 714 715 SomeArgs args = SomeArgs.obtain(); 716 args.arg1 = token; 717 args.arg2 = sessionId; 718 args.argi1 = userId; 719 args.arg3 = receiver; 720 args.arg4 = opPackageName; 721 args.arg5 = bundle; 722 args.argi2 = callingUid; 723 args.argi3 = callingPid; 724 args.argi4 = callingUserId; 725 args.arg6 = callback; 726 727 mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget(); 728 } 729 730 @Override // Binder call onConfirmDeviceCredentialSuccess()731 public void onConfirmDeviceCredentialSuccess() { 732 checkInternalPermission(); 733 734 mHandler.sendEmptyMessage(MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS); 735 } 736 737 @Override // Binder call onConfirmDeviceCredentialError(int error, String message)738 public void onConfirmDeviceCredentialError(int error, String message) { 739 checkInternalPermission(); 740 741 SomeArgs args = SomeArgs.obtain(); 742 args.argi1 = error; 743 args.arg1 = message; 744 mHandler.obtainMessage(MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR, args).sendToTarget(); 745 } 746 747 @Override // Binder call registerCancellationCallback( IBiometricConfirmDeviceCredentialCallback callback)748 public void registerCancellationCallback( 749 IBiometricConfirmDeviceCredentialCallback callback) { 750 // TODO(b/123378871): Remove when moved. 751 // This callback replaces the one stored in the current session. If the session is null 752 // we can ignore this, since it means ConfirmDeviceCredential was launched by something 753 // else (not BiometricPrompt) 754 checkInternalPermission(); 755 756 mHandler.obtainMessage(MSG_REGISTER_CANCELLATION_CALLBACK, callback).sendToTarget(); 757 } 758 759 @Override // Binder call cancelAuthentication(IBinder token, String opPackageName)760 public void cancelAuthentication(IBinder token, String opPackageName) 761 throws RemoteException { 762 checkPermission(); 763 764 SomeArgs args = SomeArgs.obtain(); 765 args.arg1 = token; 766 args.arg2 = opPackageName; 767 mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION, args).sendToTarget(); 768 } 769 770 @Override // Binder call canAuthenticate(String opPackageName, int userId)771 public int canAuthenticate(String opPackageName, int userId) { 772 Slog.d(TAG, "canAuthenticate: User=" + userId 773 + ", Caller=" + UserHandle.getCallingUserId()); 774 775 if (userId != UserHandle.getCallingUserId()) { 776 checkInternalPermission(); 777 } else { 778 checkPermission(); 779 } 780 781 final long ident = Binder.clearCallingIdentity(); 782 int error; 783 try { 784 final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId); 785 error = result.second; 786 } finally { 787 Binder.restoreCallingIdentity(ident); 788 } 789 return error; 790 } 791 792 @Override hasEnrolledBiometrics(int userId)793 public boolean hasEnrolledBiometrics(int userId) { 794 checkInternalPermission(); 795 796 final long ident = Binder.clearCallingIdentity(); 797 try { 798 for (int i = 0; i < mAuthenticators.size(); i++) { 799 if (mAuthenticators.get(i).mAuthenticator.hasEnrolledTemplates(userId)) { 800 return true; 801 } 802 } 803 } finally { 804 Binder.restoreCallingIdentity(ident); 805 } 806 return false; 807 } 808 809 @Override // Binder call registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback)810 public void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback) 811 throws RemoteException { 812 checkInternalPermission(); 813 mEnabledOnKeyguardCallbacks.add(new EnabledOnKeyguardCallback(callback)); 814 try { 815 callback.onChanged(BiometricSourceType.FACE, 816 mSettingObserver.getFaceEnabledOnKeyguard(), 817 UserHandle.getCallingUserId()); 818 } catch (RemoteException e) { 819 Slog.w(TAG, "Remote exception", e); 820 } 821 } 822 823 @Override // Binder call setActiveUser(int userId)824 public void setActiveUser(int userId) { 825 checkInternalPermission(); 826 final long ident = Binder.clearCallingIdentity(); 827 try { 828 for (int i = 0; i < mAuthenticators.size(); i++) { 829 mAuthenticators.get(i).getAuthenticator().setActiveUser(userId); 830 } 831 } finally { 832 Binder.restoreCallingIdentity(ident); 833 } 834 } 835 836 @Override // Binder call resetLockout(byte[] token)837 public void resetLockout(byte[] token) { 838 checkInternalPermission(); 839 final long ident = Binder.clearCallingIdentity(); 840 try { 841 if (mFingerprintService != null) { 842 mFingerprintService.resetTimeout(token); 843 } 844 if (mFaceService != null) { 845 mFaceService.resetLockout(token); 846 } 847 } catch (RemoteException e) { 848 Slog.e(TAG, "Remote exception", e); 849 } finally { 850 Binder.restoreCallingIdentity(ident); 851 } 852 } 853 } 854 checkAppOp(String opPackageName, int callingUid)855 private void checkAppOp(String opPackageName, int callingUid) { 856 if (mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, callingUid, 857 opPackageName) != AppOpsManager.MODE_ALLOWED) { 858 Slog.w(TAG, "Rejecting " + opPackageName + "; permission denied"); 859 throw new SecurityException("Permission denied"); 860 } 861 } 862 checkInternalPermission()863 private void checkInternalPermission() { 864 getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL, 865 "Must have USE_BIOMETRIC_INTERNAL permission"); 866 } 867 checkPermission()868 private void checkPermission() { 869 if (getContext().checkCallingOrSelfPermission(USE_FINGERPRINT) 870 != PackageManager.PERMISSION_GRANTED) { 871 getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC, 872 "Must have USE_BIOMETRIC permission"); 873 } 874 } 875 876 /** 877 * Initializes the system service. 878 * <p> 879 * Subclasses must define a single argument constructor that accepts the context 880 * and passes it to super. 881 * </p> 882 * 883 * @param context The system server context. 884 */ BiometricService(Context context)885 public BiometricService(Context context) { 886 super(context); 887 888 mAppOps = context.getSystemService(AppOpsManager.class); 889 mEnabledOnKeyguardCallbacks = new ArrayList<>(); 890 mSettingObserver = new SettingObserver(mHandler); 891 892 final PackageManager pm = context.getPackageManager(); 893 mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT); 894 mHasFeatureIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS); 895 mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE); 896 897 try { 898 ActivityManager.getService().registerUserSwitchObserver( 899 new UserSwitchObserver() { 900 @Override 901 public void onUserSwitchComplete(int newUserId) { 902 mSettingObserver.updateContentObserver(); 903 mSettingObserver.notifyEnabledOnKeyguardCallbacks(newUserId); 904 } 905 }, BiometricService.class.getName() 906 ); 907 } catch (RemoteException e) { 908 Slog.e(TAG, "Failed to register user switch observer", e); 909 } 910 } 911 912 @Override onStart()913 public void onStart() { 914 // TODO: maybe get these on-demand 915 if (mHasFeatureFingerprint) { 916 mFingerprintService = IFingerprintService.Stub.asInterface( 917 ServiceManager.getService(Context.FINGERPRINT_SERVICE)); 918 } 919 if (mHasFeatureFace) { 920 mFaceService = IFaceService.Stub.asInterface( 921 ServiceManager.getService(Context.FACE_SERVICE)); 922 } 923 924 mActivityTaskManager = ActivityTaskManager.getService(); 925 mStatusBarService = IStatusBarService.Stub.asInterface( 926 ServiceManager.getService(Context.STATUS_BAR_SERVICE)); 927 928 // Cache the authenticators 929 for (int i = 0; i < FEATURE_ID.length; i++) { 930 if (hasFeature(FEATURE_ID[i])) { 931 Authenticator authenticator = 932 new Authenticator(FEATURE_ID[i], getAuthenticator(FEATURE_ID[i])); 933 mAuthenticators.add(authenticator); 934 } 935 } 936 937 publishBinderService(Context.BIOMETRIC_SERVICE, new BiometricServiceWrapper()); 938 } 939 940 /** 941 * Checks if there are any available biometrics, and returns the modality. This method also 942 * returns errors through the callback (no biometric feature, hardware not detected, no 943 * templates enrolled, etc). This service must not start authentication if errors are sent. 944 * 945 * @Returns A pair [Modality, Error] with Modality being one of 946 * {@link BiometricAuthenticator#TYPE_NONE}, 947 * {@link BiometricAuthenticator#TYPE_FINGERPRINT}, 948 * {@link BiometricAuthenticator#TYPE_IRIS}, 949 * {@link BiometricAuthenticator#TYPE_FACE} 950 * and the error containing one of the {@link BiometricConstants} errors. 951 */ checkAndGetBiometricModality(int userId)952 private Pair<Integer, Integer> checkAndGetBiometricModality(int userId) { 953 int modality = TYPE_NONE; 954 955 // No biometric features, send error 956 if (mAuthenticators.isEmpty()) { 957 return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT); 958 } 959 960 // Assuming that authenticators are listed in priority-order, the rest of this function 961 // will go through and find the first authenticator that's available, enrolled, and enabled. 962 // The tricky part is returning the correct error. Error strings that are modality-specific 963 // should also respect the priority-order. 964 965 // Find first authenticator that's detected, enrolled, and enabled. 966 boolean isHardwareDetected = false; 967 boolean hasTemplatesEnrolled = false; 968 boolean enabledForApps = false; 969 970 int firstHwAvailable = TYPE_NONE; 971 for (int i = 0; i < mAuthenticators.size(); i++) { 972 modality = mAuthenticators.get(i).getType(); 973 BiometricAuthenticator authenticator = mAuthenticators.get(i).getAuthenticator(); 974 if (authenticator.isHardwareDetected()) { 975 isHardwareDetected = true; 976 if (firstHwAvailable == TYPE_NONE) { 977 // Store the first one since we want to return the error in correct priority 978 // order. 979 firstHwAvailable = modality; 980 } 981 if (authenticator.hasEnrolledTemplates(userId)) { 982 hasTemplatesEnrolled = true; 983 if (isEnabledForApp(modality, userId)) { 984 // TODO(b/110907543): When face settings (and other settings) have both a 985 // user toggle as well as a work profile settings page, this needs to be 986 // updated to reflect the correct setting. 987 enabledForApps = true; 988 break; 989 } 990 } 991 } 992 } 993 994 Slog.d(TAG, "checkAndGetBiometricModality: user=" + userId 995 + " isHardwareDetected=" + isHardwareDetected 996 + " hasTemplatesEnrolled=" + hasTemplatesEnrolled 997 + " enabledForApps=" + enabledForApps); 998 999 // Check error conditions 1000 if (!isHardwareDetected) { 1001 return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE); 1002 } else if (!hasTemplatesEnrolled) { 1003 // Return the modality here so the correct error string can be sent. This error is 1004 // preferred over !enabledForApps 1005 return new Pair<>(firstHwAvailable, BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS); 1006 } else if (!enabledForApps) { 1007 return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE); 1008 } 1009 1010 return new Pair<>(modality, BiometricConstants.BIOMETRIC_SUCCESS); 1011 } 1012 isEnabledForApp(int modality, int userId)1013 private boolean isEnabledForApp(int modality, int userId) { 1014 switch(modality) { 1015 case TYPE_FINGERPRINT: 1016 return true; 1017 case TYPE_IRIS: 1018 return true; 1019 case TYPE_FACE: 1020 return mSettingObserver.getFaceEnabledForApps(userId); 1021 default: 1022 Slog.w(TAG, "Unsupported modality: " + modality); 1023 return false; 1024 } 1025 } 1026 getErrorString(int type, int error, int vendorCode)1027 private String getErrorString(int type, int error, int vendorCode) { 1028 switch (type) { 1029 case TYPE_FINGERPRINT: 1030 return FingerprintManager.getErrorString(getContext(), error, vendorCode); 1031 case TYPE_IRIS: 1032 Slog.w(TAG, "Modality not supported"); 1033 return null; // not supported 1034 case TYPE_FACE: 1035 return FaceManager.getErrorString(getContext(), error, vendorCode); 1036 default: 1037 Slog.w(TAG, "Unable to get error string for modality: " + type); 1038 return null; 1039 } 1040 } 1041 getAuthenticator(int type)1042 private BiometricAuthenticator getAuthenticator(int type) { 1043 switch (type) { 1044 case TYPE_FINGERPRINT: 1045 return (FingerprintManager) 1046 getContext().getSystemService(Context.FINGERPRINT_SERVICE); 1047 case TYPE_IRIS: 1048 return null; 1049 case TYPE_FACE: 1050 return (FaceManager) 1051 getContext().getSystemService(Context.FACE_SERVICE); 1052 default: 1053 return null; 1054 } 1055 } 1056 hasFeature(int type)1057 private boolean hasFeature(int type) { 1058 switch (type) { 1059 case TYPE_FINGERPRINT: 1060 return mHasFeatureFingerprint; 1061 case TYPE_IRIS: 1062 return mHasFeatureIris; 1063 case TYPE_FACE: 1064 return mHasFeatureFace; 1065 default: 1066 return false; 1067 } 1068 } 1069 logDialogDismissed(int reason)1070 private void logDialogDismissed(int reason) { 1071 if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) { 1072 // Explicit auth, authentication confirmed. 1073 // Latency in this case is authenticated -> confirmed. <Biometric>Service 1074 // should have the first half (first acquired -> authenticated). 1075 final long latency = System.currentTimeMillis() 1076 - mCurrentAuthSession.mAuthenticatedTimeMs; 1077 1078 if (LoggableMonitor.DEBUG) { 1079 Slog.v(LoggableMonitor.TAG, "Confirmed! Modality: " + statsModality() 1080 + ", User: " + mCurrentAuthSession.mUserId 1081 + ", IsCrypto: " + mCurrentAuthSession.isCrypto() 1082 + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT 1083 + ", RequireConfirmation: " 1084 + mCurrentAuthSession.mRequireConfirmation 1085 + ", State: " + StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED 1086 + ", Latency: " + latency); 1087 } 1088 1089 StatsLog.write(StatsLog.BIOMETRIC_AUTHENTICATED, 1090 statsModality(), 1091 mCurrentAuthSession.mUserId, 1092 mCurrentAuthSession.isCrypto(), 1093 BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, 1094 mCurrentAuthSession.mRequireConfirmation, 1095 StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED, 1096 latency, 1097 Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId)); 1098 } else { 1099 1100 final long latency = System.currentTimeMillis() - mCurrentAuthSession.mStartTimeMs; 1101 1102 int error = reason == BiometricPrompt.DISMISSED_REASON_NEGATIVE 1103 ? BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON 1104 : reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL 1105 ? BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED 1106 : 0; 1107 if (LoggableMonitor.DEBUG) { 1108 Slog.v(LoggableMonitor.TAG, "Dismissed! Modality: " + statsModality() 1109 + ", User: " + mCurrentAuthSession.mUserId 1110 + ", IsCrypto: " + mCurrentAuthSession.isCrypto() 1111 + ", Action: " + BiometricsProtoEnums.ACTION_AUTHENTICATE 1112 + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT 1113 + ", Error: " + error 1114 + ", Latency: " + latency); 1115 } 1116 // Auth canceled 1117 StatsLog.write(StatsLog.BIOMETRIC_ERROR_OCCURRED, 1118 statsModality(), 1119 mCurrentAuthSession.mUserId, 1120 mCurrentAuthSession.isCrypto(), 1121 BiometricsProtoEnums.ACTION_AUTHENTICATE, 1122 BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, 1123 error, 1124 0 /* vendorCode */, 1125 Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId), 1126 latency); 1127 } 1128 } 1129 statsModality()1130 private int statsModality() { 1131 int modality = 0; 1132 if (mCurrentAuthSession == null) { 1133 return BiometricsProtoEnums.MODALITY_UNKNOWN; 1134 } 1135 if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FINGERPRINT) 1136 != 0) { 1137 modality |= BiometricsProtoEnums.MODALITY_FINGERPRINT; 1138 } 1139 if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_IRIS) != 0) { 1140 modality |= BiometricsProtoEnums.MODALITY_IRIS; 1141 } 1142 if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FACE) != 0) { 1143 modality |= BiometricsProtoEnums.MODALITY_FACE; 1144 } 1145 return modality; 1146 } 1147 handleTaskStackChanged()1148 private void handleTaskStackChanged() { 1149 try { 1150 final List<ActivityManager.RunningTaskInfo> runningTasks = 1151 mActivityTaskManager.getTasks(1); 1152 if (!runningTasks.isEmpty()) { 1153 final String topPackage = runningTasks.get(0).topActivity.getPackageName(); 1154 if (mCurrentAuthSession != null 1155 && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)) { 1156 mStatusBarService.hideBiometricDialog(); 1157 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); 1158 mCurrentAuthSession.mClientReceiver.onError( 1159 BiometricConstants.BIOMETRIC_ERROR_CANCELED, 1160 getContext().getString( 1161 com.android.internal.R.string.biometric_error_canceled) 1162 ); 1163 mCurrentAuthSession.mState = STATE_AUTH_IDLE; 1164 mCurrentAuthSession = null; 1165 } 1166 } 1167 } catch (RemoteException e) { 1168 Slog.e(TAG, "Unable to get running tasks", e); 1169 } 1170 } 1171 handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token)1172 private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token) { 1173 1174 try { 1175 // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded 1176 // after user dismissed/canceled dialog). 1177 if (mCurrentAuthSession == null) { 1178 Slog.e(TAG, "onAuthenticationSucceeded(): Auth session is null"); 1179 return; 1180 } 1181 1182 if (!requireConfirmation) { 1183 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); 1184 KeyStore.getInstance().addAuthToken(token); 1185 mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded(); 1186 mCurrentAuthSession.mState = STATE_AUTH_IDLE; 1187 mCurrentAuthSession = null; 1188 } else { 1189 mCurrentAuthSession.mAuthenticatedTimeMs = System.currentTimeMillis(); 1190 // Store the auth token and submit it to keystore after the confirmation 1191 // button has been pressed. 1192 mCurrentAuthSession.mTokenEscrow = token; 1193 mCurrentAuthSession.mState = STATE_AUTH_PENDING_CONFIRM; 1194 } 1195 1196 // Notify SysUI that the biometric has been authenticated. SysUI already knows 1197 // the implicit/explicit state and will react accordingly. 1198 mStatusBarService.onBiometricAuthenticated(true, null /* failureReason */); 1199 } catch (RemoteException e) { 1200 Slog.e(TAG, "Remote exception", e); 1201 } 1202 } 1203 handleAuthenticationFailed(String failureReason)1204 private void handleAuthenticationFailed(String failureReason) { 1205 try { 1206 // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded 1207 // after user dismissed/canceled dialog). 1208 if (mCurrentAuthSession == null) { 1209 Slog.e(TAG, "onAuthenticationFailed(): Auth session is null"); 1210 return; 1211 } 1212 1213 mStatusBarService.onBiometricAuthenticated(false, failureReason); 1214 1215 // TODO: This logic will need to be updated if BP is multi-modal 1216 if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) { 1217 // Pause authentication. onBiometricAuthenticated(false) causes the 1218 // dialog to show a "try again" button for passive modalities. 1219 mCurrentAuthSession.mState = STATE_AUTH_PAUSED; 1220 } 1221 1222 mCurrentAuthSession.mClientReceiver.onAuthenticationFailed(); 1223 } catch (RemoteException e) { 1224 Slog.e(TAG, "Remote exception", e); 1225 } 1226 } 1227 handleOnConfirmDeviceCredentialSuccess()1228 private void handleOnConfirmDeviceCredentialSuccess() { 1229 if (mConfirmDeviceCredentialReceiver == null) { 1230 Slog.w(TAG, "onCDCASuccess null!"); 1231 return; 1232 } 1233 try { 1234 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); 1235 mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded(); 1236 if (mCurrentAuthSession != null) { 1237 mCurrentAuthSession.mState = STATE_AUTH_IDLE; 1238 mCurrentAuthSession = null; 1239 } 1240 } catch (RemoteException e) { 1241 Slog.e(TAG, "RemoteException", e); 1242 } 1243 mConfirmDeviceCredentialReceiver = null; 1244 } 1245 handleOnConfirmDeviceCredentialError(int error, String message)1246 private void handleOnConfirmDeviceCredentialError(int error, String message) { 1247 if (mConfirmDeviceCredentialReceiver == null) { 1248 Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message); 1249 return; 1250 } 1251 try { 1252 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); 1253 mConfirmDeviceCredentialReceiver.onError(error, message); 1254 if (mCurrentAuthSession != null) { 1255 mCurrentAuthSession.mState = STATE_AUTH_IDLE; 1256 mCurrentAuthSession = null; 1257 } 1258 } catch (RemoteException e) { 1259 Slog.e(TAG, "RemoteException", e); 1260 } 1261 mConfirmDeviceCredentialReceiver = null; 1262 } 1263 handleRegisterCancellationCallback( IBiometricConfirmDeviceCredentialCallback callback)1264 private void handleRegisterCancellationCallback( 1265 IBiometricConfirmDeviceCredentialCallback callback) { 1266 if (mCurrentAuthSession == null) { 1267 Slog.d(TAG, "Current auth session null"); 1268 return; 1269 } 1270 Slog.d(TAG, "Updating cancel callback"); 1271 mCurrentAuthSession.mConfirmDeviceCredentialCallback = callback; 1272 } 1273 handleOnError(int cookie, int error, String message)1274 private void handleOnError(int cookie, int error, String message) { 1275 Slog.d(TAG, "Error: " + error + " cookie: " + cookie); 1276 // Errors can either be from the current auth session or the pending auth session. 1277 // The pending auth session may receive errors such as ERROR_LOCKOUT before 1278 // it becomes the current auth session. Similarly, the current auth session may 1279 // receive errors such as ERROR_CANCELED while the pending auth session is preparing 1280 // to be started. Thus we must match error messages with their cookies to be sure 1281 // of their intended receivers. 1282 try { 1283 if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) { 1284 1285 if (mCurrentAuthSession.isFromConfirmDeviceCredential()) { 1286 // If we were invoked by ConfirmDeviceCredential, do not delete the current 1287 // auth session since we still need to respond to cancel signal while 1288 if (DEBUG) Slog.d(TAG, "From CDC, transition to CANCELED_SHOWING_CDC state"); 1289 1290 // Send the error to ConfirmDeviceCredential so that it goes to Pin/Pattern/Pass 1291 // screen 1292 mCurrentAuthSession.mClientReceiver.onError(error, message); 1293 mCurrentAuthSession.mState = STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC; 1294 mStatusBarService.hideBiometricDialog(); 1295 } else if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) { 1296 mStatusBarService.onBiometricError(message); 1297 if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) { 1298 mActivityTaskManager.unregisterTaskStackListener( 1299 mTaskStackListener); 1300 mCurrentAuthSession.mClientReceiver.onError(error, message); 1301 mCurrentAuthSession.mState = STATE_AUTH_IDLE; 1302 mCurrentAuthSession = null; 1303 mStatusBarService.hideBiometricDialog(); 1304 } else { 1305 // Send errors after the dialog is dismissed. 1306 mHandler.postDelayed(() -> { 1307 try { 1308 if (mCurrentAuthSession != null) { 1309 mActivityTaskManager.unregisterTaskStackListener( 1310 mTaskStackListener); 1311 mCurrentAuthSession.mClientReceiver.onError(error, 1312 message); 1313 mCurrentAuthSession.mState = STATE_AUTH_IDLE; 1314 mCurrentAuthSession = null; 1315 } 1316 } catch (RemoteException e) { 1317 Slog.e(TAG, "Remote exception", e); 1318 } 1319 }, BiometricPrompt.HIDE_DIALOG_DELAY); 1320 } 1321 } else if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED) { 1322 // In the "try again" state, we should forward canceled errors to 1323 // the client and and clean up. 1324 mCurrentAuthSession.mClientReceiver.onError(error, message); 1325 mStatusBarService.onBiometricError(message); 1326 mActivityTaskManager.unregisterTaskStackListener( 1327 mTaskStackListener); 1328 mCurrentAuthSession.mState = STATE_AUTH_IDLE; 1329 mCurrentAuthSession = null; 1330 } else { 1331 Slog.e(TAG, "Impossible session error state: " 1332 + mCurrentAuthSession.mState); 1333 } 1334 } else if (mPendingAuthSession != null 1335 && mPendingAuthSession.containsCookie(cookie)) { 1336 if (mPendingAuthSession.mState == STATE_AUTH_CALLED) { 1337 mPendingAuthSession.mClientReceiver.onError(error, message); 1338 mPendingAuthSession.mState = STATE_AUTH_IDLE; 1339 mPendingAuthSession = null; 1340 } else { 1341 Slog.e(TAG, "Impossible pending session error state: " 1342 + mPendingAuthSession.mState); 1343 } 1344 } 1345 } catch (RemoteException e) { 1346 Slog.e(TAG, "Remote exception", e); 1347 } 1348 } 1349 handleOnAcquired(int acquiredInfo, String message)1350 private void handleOnAcquired(int acquiredInfo, String message) { 1351 // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded 1352 // after user dismissed/canceled dialog). 1353 if (mCurrentAuthSession == null) { 1354 Slog.e(TAG, "onAcquired(): Auth session is null"); 1355 return; 1356 } 1357 1358 if (acquiredInfo != BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) { 1359 if (message == null) { 1360 Slog.w(TAG, "Ignoring null message: " + acquiredInfo); 1361 return; 1362 } 1363 try { 1364 mStatusBarService.onBiometricHelp(message); 1365 } catch (RemoteException e) { 1366 Slog.e(TAG, "Remote exception", e); 1367 } 1368 } 1369 } 1370 handleOnDismissed(int reason)1371 private void handleOnDismissed(int reason) { 1372 if (mCurrentAuthSession == null) { 1373 Slog.e(TAG, "onDialogDismissed: " + reason + ", auth session null"); 1374 return; 1375 } 1376 1377 logDialogDismissed(reason); 1378 1379 try { 1380 if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) { 1381 // Positive button is used by passive modalities as a "confirm" button, 1382 // do not send to client 1383 mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason); 1384 // Cancel authentication. Skip the token/package check since we are cancelling 1385 // from system server. The interface is permission protected so this is fine. 1386 cancelInternal(null /* token */, null /* package */, false /* fromClient */); 1387 } 1388 if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) { 1389 mCurrentAuthSession.mClientReceiver.onError( 1390 BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED, 1391 getContext().getString( 1392 com.android.internal.R.string.biometric_error_user_canceled)); 1393 } else if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) { 1394 // Have the service send the token to KeyStore, and send onAuthenticated 1395 // to the application 1396 KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow); 1397 mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded(); 1398 } 1399 1400 // Do not clean up yet if we are from ConfirmDeviceCredential. We should be in the 1401 // STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC. The session should only be removed when 1402 // ConfirmDeviceCredential is confirmed or canceled. 1403 // TODO(b/123378871): Remove when moved 1404 if (!mCurrentAuthSession.isFromConfirmDeviceCredential()) { 1405 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); 1406 mCurrentAuthSession.mState = STATE_AUTH_IDLE; 1407 mCurrentAuthSession = null; 1408 } 1409 } catch (RemoteException e) { 1410 Slog.e(TAG, "Remote exception", e); 1411 } 1412 } 1413 handleOnTryAgainPressed()1414 private void handleOnTryAgainPressed() { 1415 Slog.d(TAG, "onTryAgainPressed"); 1416 // No need to check permission, since it can only be invoked by SystemUI 1417 // (or system server itself). 1418 authenticateInternal(mCurrentAuthSession.mToken, 1419 mCurrentAuthSession.mSessionId, 1420 mCurrentAuthSession.mUserId, 1421 mCurrentAuthSession.mClientReceiver, 1422 mCurrentAuthSession.mOpPackageName, 1423 mCurrentAuthSession.mBundle, 1424 mCurrentAuthSession.mCallingUid, 1425 mCurrentAuthSession.mCallingPid, 1426 mCurrentAuthSession.mCallingUserId, 1427 mCurrentAuthSession.mModality, 1428 mCurrentAuthSession.mConfirmDeviceCredentialCallback); 1429 } 1430 handleOnReadyForAuthentication(int cookie, boolean requireConfirmation, int userId)1431 private void handleOnReadyForAuthentication(int cookie, boolean requireConfirmation, 1432 int userId) { 1433 Iterator it = mPendingAuthSession.mModalitiesWaiting.entrySet().iterator(); 1434 while (it.hasNext()) { 1435 Map.Entry<Integer, Integer> pair = (Map.Entry) it.next(); 1436 if (pair.getValue() == cookie) { 1437 mPendingAuthSession.mModalitiesMatched.put(pair.getKey(), pair.getValue()); 1438 mPendingAuthSession.mModalitiesWaiting.remove(pair.getKey()); 1439 Slog.d(TAG, "Matched cookie: " + cookie + ", " 1440 + mPendingAuthSession.mModalitiesWaiting.size() + " remaining"); 1441 break; 1442 } 1443 } 1444 1445 if (mPendingAuthSession.mModalitiesWaiting.isEmpty()) { 1446 final boolean continuing = mCurrentAuthSession != null 1447 && mCurrentAuthSession.mState == STATE_AUTH_PAUSED; 1448 1449 mCurrentAuthSession = mPendingAuthSession; 1450 1451 // Time starts when lower layers are ready to start the client. 1452 mCurrentAuthSession.mStartTimeMs = System.currentTimeMillis(); 1453 mPendingAuthSession = null; 1454 1455 mCurrentAuthSession.mState = STATE_AUTH_STARTED; 1456 try { 1457 int modality = TYPE_NONE; 1458 it = mCurrentAuthSession.mModalitiesMatched.entrySet().iterator(); 1459 while (it.hasNext()) { 1460 Map.Entry<Integer, Integer> pair = (Map.Entry) it.next(); 1461 if (pair.getKey() == TYPE_FINGERPRINT) { 1462 mFingerprintService.startPreparedClient(pair.getValue()); 1463 } else if (pair.getKey() == TYPE_IRIS) { 1464 Slog.e(TAG, "Iris unsupported"); 1465 } else if (pair.getKey() == TYPE_FACE) { 1466 mFaceService.startPreparedClient(pair.getValue()); 1467 } else { 1468 Slog.e(TAG, "Unknown modality: " + pair.getKey()); 1469 } 1470 modality |= pair.getKey(); 1471 } 1472 1473 if (!continuing) { 1474 mStatusBarService.showBiometricDialog(mCurrentAuthSession.mBundle, 1475 mInternalReceiver, modality, requireConfirmation, userId); 1476 mActivityTaskManager.registerTaskStackListener(mTaskStackListener); 1477 } 1478 } catch (RemoteException e) { 1479 Slog.e(TAG, "Remote exception", e); 1480 } 1481 } 1482 } 1483 handleAuthenticate(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, int callingUid, int callingPid, int callingUserId, IBiometricConfirmDeviceCredentialCallback callback)1484 private void handleAuthenticate(IBinder token, long sessionId, int userId, 1485 IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, 1486 int callingUid, int callingPid, int callingUserId, 1487 IBiometricConfirmDeviceCredentialCallback callback) { 1488 1489 mHandler.post(() -> { 1490 final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId); 1491 final int modality = result.first; 1492 final int error = result.second; 1493 1494 // Check for errors, notify callback, and return 1495 if (error != BiometricConstants.BIOMETRIC_SUCCESS) { 1496 try { 1497 final String hardwareUnavailable = 1498 getContext().getString(R.string.biometric_error_hw_unavailable); 1499 switch (error) { 1500 case BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT: 1501 receiver.onError(error, hardwareUnavailable); 1502 break; 1503 case BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE: 1504 receiver.onError(error, hardwareUnavailable); 1505 break; 1506 case BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS: 1507 receiver.onError(error, 1508 getErrorString(modality, error, 0 /* vendorCode */)); 1509 break; 1510 default: 1511 Slog.e(TAG, "Unhandled error"); 1512 break; 1513 } 1514 } catch (RemoteException e) { 1515 Slog.e(TAG, "Unable to send error", e); 1516 } 1517 return; 1518 } 1519 1520 mCurrentModality = modality; 1521 1522 // Start preparing for authentication. Authentication starts when 1523 // all modalities requested have invoked onReadyForAuthentication. 1524 authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle, 1525 callingUid, callingPid, callingUserId, modality, callback); 1526 }); 1527 } 1528 1529 /** 1530 * authenticate() (above) which is called from BiometricPrompt determines which 1531 * modality/modalities to start authenticating with. authenticateInternal() should only be 1532 * used for: 1533 * 1) Preparing <Biometric>Services for authentication when BiometricPrompt#authenticate is, 1534 * invoked, shortly after which BiometricPrompt is shown and authentication starts 1535 * 2) Preparing <Biometric>Services for authentication when BiometricPrompt is already shown 1536 * and the user has pressed "try again" 1537 */ authenticateInternal(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, int callingUid, int callingPid, int callingUserId, int modality, IBiometricConfirmDeviceCredentialCallback callback)1538 private void authenticateInternal(IBinder token, long sessionId, int userId, 1539 IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, 1540 int callingUid, int callingPid, int callingUserId, int modality, 1541 IBiometricConfirmDeviceCredentialCallback callback) { 1542 try { 1543 boolean requireConfirmation = bundle.getBoolean( 1544 BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */); 1545 if ((modality & TYPE_FACE) != 0) { 1546 // Check if the user has forced confirmation to be required in Settings. 1547 requireConfirmation = requireConfirmation 1548 || mSettingObserver.getFaceAlwaysRequireConfirmation(userId); 1549 } 1550 // Generate random cookies to pass to the services that should prepare to start 1551 // authenticating. Store the cookie here and wait for all services to "ack" 1552 // with the cookie. Once all cookies are received, we can show the prompt 1553 // and let the services start authenticating. The cookie should be non-zero. 1554 final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; 1555 Slog.d(TAG, "Creating auth session. Modality: " + modality 1556 + ", cookie: " + cookie); 1557 final HashMap<Integer, Integer> authenticators = new HashMap<>(); 1558 authenticators.put(modality, cookie); 1559 mPendingAuthSession = new AuthSession(authenticators, token, sessionId, userId, 1560 receiver, opPackageName, bundle, callingUid, callingPid, callingUserId, 1561 modality, requireConfirmation, callback); 1562 mPendingAuthSession.mState = STATE_AUTH_CALLED; 1563 // No polymorphism :( 1564 if ((modality & TYPE_FINGERPRINT) != 0) { 1565 mFingerprintService.prepareForAuthentication(token, sessionId, userId, 1566 mInternalReceiver, opPackageName, cookie, 1567 callingUid, callingPid, callingUserId); 1568 } 1569 if ((modality & TYPE_IRIS) != 0) { 1570 Slog.w(TAG, "Iris unsupported"); 1571 } 1572 if ((modality & TYPE_FACE) != 0) { 1573 mFaceService.prepareForAuthentication(requireConfirmation, 1574 token, sessionId, userId, mInternalReceiver, opPackageName, 1575 cookie, callingUid, callingPid, callingUserId); 1576 } 1577 } catch (RemoteException e) { 1578 Slog.e(TAG, "Unable to start authentication", e); 1579 } 1580 } 1581 handleCancelAuthentication(IBinder token, String opPackageName)1582 private void handleCancelAuthentication(IBinder token, String opPackageName) { 1583 if (token == null || opPackageName == null) { 1584 Slog.e(TAG, "Unable to cancel, one or more null arguments"); 1585 return; 1586 } 1587 1588 if (mCurrentAuthSession != null 1589 && mCurrentAuthSession.mState == STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC) { 1590 if (DEBUG) Slog.d(TAG, "Cancel received while ConfirmDeviceCredential showing"); 1591 try { 1592 mCurrentAuthSession.mConfirmDeviceCredentialCallback.cancel(); 1593 } catch (RemoteException e) { 1594 Slog.e(TAG, "Unable to cancel ConfirmDeviceCredential", e); 1595 } 1596 1597 // TODO(b/123378871): Remove when moved. Piggy back on this for now to clean up. 1598 handleOnConfirmDeviceCredentialError(BiometricConstants.BIOMETRIC_ERROR_CANCELED, 1599 getContext().getString(R.string.biometric_error_canceled)); 1600 } else if (mCurrentAuthSession != null 1601 && mCurrentAuthSession.mState != STATE_AUTH_STARTED) { 1602 // We need to check the current authenticators state. If we're pending confirm 1603 // or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client, 1604 // since we won't be getting an onError from the driver. 1605 try { 1606 // Send error to client 1607 mCurrentAuthSession.mClientReceiver.onError( 1608 BiometricConstants.BIOMETRIC_ERROR_CANCELED, 1609 getContext().getString( 1610 com.android.internal.R.string.biometric_error_user_canceled) 1611 ); 1612 1613 mCurrentAuthSession.mState = STATE_AUTH_IDLE; 1614 mCurrentAuthSession = null; 1615 mStatusBarService.hideBiometricDialog(); 1616 } catch (RemoteException e) { 1617 Slog.e(TAG, "Remote exception", e); 1618 } 1619 } else { 1620 boolean fromCDC = false; 1621 if (mCurrentAuthSession != null) { 1622 fromCDC = mCurrentAuthSession.mBundle.getBoolean( 1623 BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false); 1624 } 1625 1626 if (fromCDC) { 1627 if (DEBUG) Slog.d(TAG, "Cancelling from CDC"); 1628 cancelInternal(token, opPackageName, false /* fromClient */); 1629 } else { 1630 cancelInternal(token, opPackageName, true /* fromClient */); 1631 } 1632 1633 } 1634 } 1635 cancelInternal(IBinder token, String opPackageName, boolean fromClient)1636 void cancelInternal(IBinder token, String opPackageName, boolean fromClient) { 1637 final int callingUid = Binder.getCallingUid(); 1638 final int callingPid = Binder.getCallingPid(); 1639 final int callingUserId = UserHandle.getCallingUserId(); 1640 mHandler.post(() -> { 1641 try { 1642 // TODO: For multiple modalities, send a single ERROR_CANCELED only when all 1643 // drivers have canceled authentication. 1644 if ((mCurrentModality & TYPE_FINGERPRINT) != 0) { 1645 mFingerprintService.cancelAuthenticationFromService(token, opPackageName, 1646 callingUid, callingPid, callingUserId, fromClient); 1647 } 1648 if ((mCurrentModality & TYPE_IRIS) != 0) { 1649 Slog.w(TAG, "Iris unsupported"); 1650 } 1651 if ((mCurrentModality & TYPE_FACE) != 0) { 1652 mFaceService.cancelAuthenticationFromService(token, opPackageName, 1653 callingUid, callingPid, callingUserId, fromClient); 1654 } 1655 } catch (RemoteException e) { 1656 Slog.e(TAG, "Unable to cancel authentication"); 1657 } 1658 }); 1659 } 1660 1661 } 1662