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