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.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
20 
21 import android.app.ActivityManager;
22 import android.app.ActivityTaskManager;
23 import android.app.AppOpsManager;
24 import android.app.IActivityTaskManager;
25 import android.app.SynchronousUserSwitchObserver;
26 import android.app.TaskStackListener;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.pm.PackageManager;
30 import android.content.pm.UserInfo;
31 import android.hardware.biometrics.BiometricAuthenticator;
32 import android.hardware.biometrics.BiometricConstants;
33 import android.hardware.biometrics.BiometricsProtoEnums;
34 import android.hardware.biometrics.IBiometricService;
35 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
36 import android.hardware.biometrics.IBiometricServiceReceiverInternal;
37 import android.hardware.fingerprint.Fingerprint;
38 import android.os.Binder;
39 import android.os.Bundle;
40 import android.os.DeadObjectException;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.IHwBinder;
44 import android.os.IRemoteCallback;
45 import android.os.PowerManager;
46 import android.os.Process;
47 import android.os.RemoteException;
48 import android.os.ServiceManager;
49 import android.os.SystemClock;
50 import android.os.UserHandle;
51 import android.os.UserManager;
52 import android.util.Slog;
53 import android.util.StatsLog;
54 
55 import com.android.internal.logging.MetricsLogger;
56 import com.android.internal.statusbar.IStatusBarService;
57 import com.android.server.SystemService;
58 
59 import java.util.ArrayList;
60 import java.util.Collections;
61 import java.util.HashMap;
62 import java.util.List;
63 import java.util.Map;
64 
65 /**
66  * Abstract base class containing all of the business logic for biometric services, e.g.
67  * Fingerprint, Face, Iris.
68  *
69  * @hide
70  */
71 public abstract class BiometricServiceBase extends SystemService
72         implements IHwBinder.DeathRecipient {
73 
74     protected static final boolean DEBUG = true;
75 
76     private static final boolean CLEANUP_UNKNOWN_TEMPLATES = true;
77     private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
78     private static final int MSG_USER_SWITCHING = 10;
79     private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
80 
81     private final Context mContext;
82     private final String mKeyguardPackage;
83     private final IActivityTaskManager mActivityTaskManager;
84     private final PowerManager mPowerManager;
85     private final UserManager mUserManager;
86     private final MetricsLogger mMetricsLogger;
87     private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
88     private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable();
89     private final ArrayList<LockoutResetMonitor> mLockoutMonitors = new ArrayList<>();
90 
91     protected final IStatusBarService mStatusBarService;
92     protected final Map<Integer, Long> mAuthenticatorIds =
93             Collections.synchronizedMap(new HashMap<>());
94     protected final AppOpsManager mAppOps;
95     protected final H mHandler = new H();
96 
97     private final IBinder mToken = new Binder(); // Used for internal enumeration
98     private final ArrayList<UserTemplate> mUnknownHALTemplates = new ArrayList<>();
99 
100     private IBiometricService mBiometricService;
101     private ClientMonitor mCurrentClient;
102     private ClientMonitor mPendingClient;
103     private PerformanceStats mPerformanceStats;
104     protected int mCurrentUserId = UserHandle.USER_NULL;
105     protected long mHalDeviceId;
106     // Tracks if the current authentication makes use of CryptoObjects.
107     protected boolean mIsCrypto;
108     // Normal authentications are tracked by mPerformanceMap.
109     protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
110     // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
111     protected HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
112     protected int mHALDeathCount;
113 
114     protected class PerformanceStats {
115         public int accept; // number of accepted biometrics
116         public int reject; // number of rejected biometrics
117         public int acquire; // total number of acquisitions. Should be >= accept+reject due to poor
118         // image acquisition in some cases (too fast, too slow, dirty sensor, etc.)
119         public int lockout; // total number of lockouts
120         public int permanentLockout; // total number of permanent lockouts
121     }
122 
123     /**
124      * @return the log tag.
125      */
getTag()126     protected abstract String getTag();
127 
128     /**
129      * @return wrapper for the HAL
130      */
getDaemonWrapper()131     protected abstract DaemonWrapper getDaemonWrapper();
132 
133     /**
134      * @return the biometric utilities for a specific implementation.
135      */
getBiometricUtils()136     protected abstract BiometricUtils getBiometricUtils();
137 
138     /**
139      * @return the metrics constants for a biometric implementation.
140      */
getConstants()141     protected abstract Constants getConstants();
142 
143     /**
144      * @param userId
145      * @return true if the enrollment limit has been reached.
146      */
hasReachedEnrollmentLimit(int userId)147     protected abstract boolean hasReachedEnrollmentLimit(int userId);
148 
149     /**
150      * Notifies the HAL that the user has changed.
151      * @param userId
152      * @param clientPackage
153      */
updateActiveGroup(int userId, String clientPackage)154     protected abstract void updateActiveGroup(int userId, String clientPackage);
155 
156     /**
157      * @return The protected intent to reset lockout for a specific biometric.
158      */
getLockoutResetIntent()159     protected abstract String getLockoutResetIntent();
160 
161     /**
162      * @return The permission the sender is required to have in order for the lockout reset intent
163      *         to be received by the BiometricService implementation.
164      */
getLockoutBroadcastPermission()165     protected abstract String getLockoutBroadcastPermission();
166 
167     /**
168      * @return The HAL ID.
169      */
getHalDeviceId()170     protected abstract long getHalDeviceId();
171 
172     /**
173      * @param userId
174      * @return Returns true if the user has any enrolled biometrics.
175      */
hasEnrolledBiometrics(int userId)176     protected abstract boolean hasEnrolledBiometrics(int userId);
177 
178     /**
179      * @return Returns the MANAGE_* permission string, which is required for enrollment, removal
180      * etc.
181      */
getManageBiometricPermission()182     protected abstract String getManageBiometricPermission();
183 
184     /**
185      * Checks if the caller has permission to use the biometric service - throws a SecurityException
186      * if not.
187      */
checkUseBiometricPermission()188     protected abstract void checkUseBiometricPermission();
189 
190     /**
191      * Checks if the caller passes the app ops check
192      */
checkAppOps(int uid, String opPackageName)193     protected abstract boolean checkAppOps(int uid, String opPackageName);
194 
getEnrolledTemplates( int userId)195     protected abstract List<? extends BiometricAuthenticator.Identifier> getEnrolledTemplates(
196             int userId);
197 
198     /**
199      * Notifies clients of any change in the biometric state (active / idle). This is mainly for
200      * Fingerprint navigation gestures.
201      * @param isActive
202      */
notifyClientActiveCallbacks(boolean isActive)203     protected void notifyClientActiveCallbacks(boolean isActive) {}
204 
statsModality()205     protected abstract int statsModality();
206 
207     /**
208      * @return one of the AuthenticationClient LOCKOUT constants
209      */
getLockoutMode()210     protected abstract int getLockoutMode();
211 
212     protected abstract class AuthenticationClientImpl extends AuthenticationClient {
213 
214         // Used to check if the public API that was invoked was from FingerprintManager. Only
215         // to be overridden by FingerprintService.
isFingerprint()216         protected boolean isFingerprint() {
217             return false;
218         }
219 
AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId, IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId, boolean restricted, String owner, int cookie, boolean requireConfirmation)220         public AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
221                 IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId,
222                 boolean restricted, String owner, int cookie, boolean requireConfirmation) {
223             super(context, getConstants(), daemon, halDeviceId, token, listener, targetUserId,
224                     groupId, opId, restricted, owner, cookie, requireConfirmation);
225         }
226 
227         @Override
statsClient()228         protected int statsClient() {
229             if (isKeyguard(getOwnerString())) {
230                 return BiometricsProtoEnums.CLIENT_KEYGUARD;
231             } else if (isBiometricPrompt()) {
232                 return BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT;
233             } else if (isFingerprint()) {
234                 return BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER;
235             } else {
236                 return BiometricsProtoEnums.CLIENT_UNKNOWN;
237             }
238         }
239 
240         @Override
onStart()241         public void onStart() {
242             try {
243                 mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
244             } catch (RemoteException e) {
245                 Slog.e(getTag(), "Could not register task stack listener", e);
246             }
247         }
248 
249         @Override
onStop()250         public void onStop() {
251             try {
252                 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
253             } catch (RemoteException e) {
254                 Slog.e(getTag(), "Could not unregister task stack listener", e);
255             }
256         }
257 
258         @Override
notifyUserActivity()259         public void notifyUserActivity() {
260             userActivity();
261         }
262 
263         @Override
handleFailedAttempt()264         public int handleFailedAttempt() {
265             final int lockoutMode = getLockoutMode();
266             if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
267                 mPerformanceStats.permanentLockout++;
268             } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
269                 mPerformanceStats.lockout++;
270             }
271 
272             // Failing multiple times will continue to push out the lockout time
273             if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
274                 return lockoutMode;
275             }
276             return AuthenticationClient.LOCKOUT_NONE;
277         }
278     }
279 
280     protected abstract class EnrollClientImpl extends EnrollClient {
281 
EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId, IBinder token, ServiceListener listener, int userId, int groupId, byte[] cryptoToken, boolean restricted, String owner, final int[] disabledFeatures, int timeoutSec)282         public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
283                 IBinder token, ServiceListener listener, int userId, int groupId,
284                 byte[] cryptoToken, boolean restricted, String owner,
285                 final int[] disabledFeatures, int timeoutSec) {
286             super(context, getConstants(), daemon, halDeviceId, token, listener,
287                     userId, groupId, cryptoToken, restricted, owner, getBiometricUtils(),
288                     disabledFeatures, timeoutSec);
289         }
290 
291         @Override
notifyUserActivity()292         public void notifyUserActivity() {
293             userActivity();
294         }
295     }
296 
297     /**
298      * An internal class to help clean up unknown templates in HAL and Framework
299      */
300     private final class InternalRemovalClient extends RemovalClient {
InternalRemovalClient(Context context, DaemonWrapper daemon, long halDeviceId, IBinder token, ServiceListener listener, int templateId, int groupId, int userId, boolean restricted, String owner)301         InternalRemovalClient(Context context,
302                 DaemonWrapper daemon, long halDeviceId, IBinder token,
303                 ServiceListener listener, int templateId, int groupId, int userId,
304                 boolean restricted, String owner) {
305             super(context, getConstants(), daemon, halDeviceId, token, listener, templateId, groupId,
306                     userId, restricted, owner, getBiometricUtils());
307         }
308 
309         @Override
statsModality()310         protected int statsModality() {
311             return BiometricServiceBase.this.statsModality();
312         }
313     }
314 
315     /**
316      * Internal class to help clean up unknown templates in the HAL and Framework
317      */
318     private final class InternalEnumerateClient extends EnumerateClient {
319 
320         private BiometricUtils mUtils;
321         // List of templates that are known to the Framework. Remove from this list when enumerate
322         // returns a template that contains a match.
323         private List<? extends BiometricAuthenticator.Identifier> mEnrolledList;
324         // List of templates to remove from the HAL
325         private List<BiometricAuthenticator.Identifier> mUnknownHALTemplates = new ArrayList<>();
326 
InternalEnumerateClient(Context context, DaemonWrapper daemon, long halDeviceId, IBinder token, ServiceListener listener, int groupId, int userId, boolean restricted, String owner, List<? extends BiometricAuthenticator.Identifier> enrolledList, BiometricUtils utils)327         InternalEnumerateClient(Context context,
328                 DaemonWrapper daemon, long halDeviceId, IBinder token,
329                 ServiceListener listener, int groupId, int userId, boolean restricted,
330                 String owner, List<? extends BiometricAuthenticator.Identifier> enrolledList,
331                 BiometricUtils utils) {
332             super(context, getConstants(), daemon, halDeviceId, token, listener, groupId, userId,
333                     restricted, owner);
334             mEnrolledList = enrolledList;
335             mUtils = utils;
336         }
337 
handleEnumeratedTemplate(BiometricAuthenticator.Identifier identifier)338         private void handleEnumeratedTemplate(BiometricAuthenticator.Identifier identifier) {
339             if (identifier == null) {
340                 return;
341             }
342             Slog.v(getTag(), "handleEnumeratedTemplate: " + identifier.getBiometricId());
343             boolean matched = false;
344             for (int i = 0; i < mEnrolledList.size(); i++) {
345                 if (mEnrolledList.get(i).getBiometricId() == identifier.getBiometricId()) {
346                     mEnrolledList.remove(i);
347                     matched = true;
348                     break;
349                 }
350             }
351 
352             // TemplateId 0 means no templates in HAL
353             if (!matched && identifier.getBiometricId() != 0) {
354                 mUnknownHALTemplates.add(identifier);
355             }
356             Slog.v(getTag(), "Matched: " + matched);
357         }
358 
doTemplateCleanup()359         private void doTemplateCleanup() {
360             if (mEnrolledList == null) {
361                 return;
362             }
363 
364             // At this point, mEnrolledList only contains templates known to the framework and
365             // not the HAL.
366             for (int i = 0; i < mEnrolledList.size(); i++) {
367                 BiometricAuthenticator.Identifier identifier = mEnrolledList.get(i);
368                 Slog.e(getTag(), "doTemplateCleanup(): Removing dangling template from framework: "
369                         + identifier.getBiometricId() + " "
370                         + identifier.getName());
371                 mUtils.removeBiometricForUser(getContext(),
372                         getTargetUserId(), identifier.getBiometricId());
373                 StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
374                         statsModality(),
375                         BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK);
376             }
377             mEnrolledList.clear();
378         }
379 
getUnknownHALTemplates()380         public List<BiometricAuthenticator.Identifier> getUnknownHALTemplates() {
381             return mUnknownHALTemplates;
382         }
383 
384         @Override
onEnumerationResult(BiometricAuthenticator.Identifier identifier, int remaining)385         public boolean onEnumerationResult(BiometricAuthenticator.Identifier identifier,
386                 int remaining) {
387             handleEnumeratedTemplate(identifier);
388             if (remaining == 0) {
389                 doTemplateCleanup();
390             }
391             return remaining == 0;
392         }
393 
394         @Override
statsModality()395         protected int statsModality() {
396             return BiometricServiceBase.this.statsModality();
397         }
398     }
399 
400     /**
401      * Wraps the callback interface from Service -> Manager
402      */
403     protected interface ServiceListener {
onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)404         default void onEnrollResult(BiometricAuthenticator.Identifier identifier,
405                 int remaining) throws RemoteException {};
406 
onAcquired(long deviceId, int acquiredInfo, int vendorCode)407         void onAcquired(long deviceId, int acquiredInfo, int vendorCode) throws RemoteException;
408 
onAuthenticationSucceeded(long deviceId, BiometricAuthenticator.Identifier biometric, int userId)409         default void onAuthenticationSucceeded(long deviceId,
410                 BiometricAuthenticator.Identifier biometric, int userId) throws RemoteException {
411             throw new UnsupportedOperationException("Stub!");
412         }
413 
onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)414         default void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)
415                 throws RemoteException {
416             throw new UnsupportedOperationException("Stub!");
417         }
418 
onAuthenticationFailed(long deviceId)419         default void onAuthenticationFailed(long deviceId) throws RemoteException {
420             throw new UnsupportedOperationException("Stub!");
421         }
422 
onAuthenticationFailedInternal(int cookie, boolean requireConfirmation)423         default void onAuthenticationFailedInternal(int cookie, boolean requireConfirmation)
424                 throws RemoteException {
425             throw new UnsupportedOperationException("Stub!");
426         }
427 
onError(long deviceId, int error, int vendorCode, int cookie)428         void onError(long deviceId, int error, int vendorCode, int cookie) throws RemoteException;
429 
onRemoved(BiometricAuthenticator.Identifier identifier, int remaining)430         default void onRemoved(BiometricAuthenticator.Identifier identifier,
431                 int remaining) throws RemoteException {};
432 
onEnumerated(BiometricAuthenticator.Identifier identifier, int remaining)433         default void onEnumerated(BiometricAuthenticator.Identifier identifier,
434                 int remaining) throws RemoteException {};
435     }
436 
437     /**
438      * Wraps the callback interface from Service -> BiometricPrompt
439      */
440     protected abstract class BiometricServiceListener implements ServiceListener {
441         private IBiometricServiceReceiverInternal mWrapperReceiver;
442 
BiometricServiceListener(IBiometricServiceReceiverInternal wrapperReceiver)443         public BiometricServiceListener(IBiometricServiceReceiverInternal wrapperReceiver) {
444             mWrapperReceiver = wrapperReceiver;
445         }
446 
getWrapperReceiver()447         public IBiometricServiceReceiverInternal getWrapperReceiver() {
448             return mWrapperReceiver;
449         }
450 
451         @Override
onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)452         public void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)
453                 throws RemoteException {
454             if (getWrapperReceiver() != null) {
455                 getWrapperReceiver().onAuthenticationSucceeded(requireConfirmation, token);
456             }
457         }
458 
459         @Override
onAuthenticationFailedInternal(int cookie, boolean requireConfirmation)460         public void onAuthenticationFailedInternal(int cookie, boolean requireConfirmation)
461                 throws RemoteException {
462             if (getWrapperReceiver() != null) {
463                 getWrapperReceiver().onAuthenticationFailed(cookie, requireConfirmation);
464             }
465         }
466     }
467 
468     /**
469      * Wraps a portion of the interface from Service -> Daemon that is used by the ClientMonitor
470      * subclasses.
471      */
472     protected interface DaemonWrapper {
473         int ERROR_ESRCH = 3; // Likely HAL is dead. see errno.h.
authenticate(long operationId, int groupId)474         int authenticate(long operationId, int groupId) throws RemoteException;
cancel()475         int cancel() throws RemoteException;
remove(int groupId, int biometricId)476         int remove(int groupId, int biometricId) throws RemoteException;
enumerate()477         int enumerate() throws RemoteException;
enroll(byte[] token, int groupId, int timeout, ArrayList<Integer> disabledFeatures)478         int enroll(byte[] token, int groupId, int timeout,
479                 ArrayList<Integer> disabledFeatures) throws RemoteException;
resetLockout(byte[] token)480         void resetLockout(byte[] token) throws RemoteException;
481     }
482 
483     /**
484      * Handler which all subclasses should post events to.
485      */
486     protected final class H extends Handler {
487         @Override
handleMessage(android.os.Message msg)488         public void handleMessage(android.os.Message msg) {
489             switch (msg.what) {
490                 case MSG_USER_SWITCHING:
491                     handleUserSwitching(msg.arg1);
492                     break;
493 
494                 default:
495                     Slog.w(getTag(), "Unknown message:" + msg.what);
496             }
497         }
498     }
499 
500     private final Runnable mOnTaskStackChangedRunnable = new Runnable() {
501         @Override
502         public void run() {
503             try {
504                 if (!(mCurrentClient instanceof AuthenticationClient)) {
505                     return;
506                 }
507                 final String currentClient = mCurrentClient.getOwnerString();
508                 if (isKeyguard(currentClient)) {
509                     return; // Keyguard is always allowed
510                 }
511                 List<ActivityManager.RunningTaskInfo> runningTasks =
512                         mActivityTaskManager.getTasks(1);
513                 if (!runningTasks.isEmpty()) {
514                     final String topPackage = runningTasks.get(0).topActivity.getPackageName();
515                     if (!topPackage.contentEquals(currentClient)
516                             && !mCurrentClient.isAlreadyDone()) {
517                         Slog.e(getTag(), "Stopping background authentication, top: "
518                                 + topPackage + " currentClient: " + currentClient);
519                         mCurrentClient.stop(false /* initiatedByClient */);
520                     }
521                 }
522             } catch (RemoteException e) {
523                 Slog.e(getTag(), "Unable to get running tasks", e);
524             }
525         }
526     };
527 
528     private final class BiometricTaskStackListener extends TaskStackListener {
529         @Override
onTaskStackChanged()530         public void onTaskStackChanged() {
531             mHandler.post(mOnTaskStackChangedRunnable);
532         }
533     }
534 
535     private final class ResetClientStateRunnable implements Runnable {
536         @Override
run()537         public void run() {
538             /**
539              * Warning: if we get here, the driver never confirmed our call to cancel the current
540              * operation (authenticate, enroll, remove, enumerate, etc), which is
541              * really bad.  The result will be a 3-second delay in starting each new client.
542              * If you see this on a device, make certain the driver notifies with
543              * {@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} in response to cancel()
544              * once it has successfully switched to the IDLE state in the HAL.
545              * Additionally,{@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} should only be sent
546              * in response to an actual cancel() call.
547              */
548             Slog.w(getTag(), "Client "
549                     + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
550                     + " failed to respond to cancel, starting client "
551                     + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
552 
553             StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
554                     statsModality(), BiometricsProtoEnums.ISSUE_CANCEL_TIMED_OUT);
555 
556             mCurrentClient = null;
557             startClient(mPendingClient, false);
558         }
559     }
560 
561 
562 
563     private final class LockoutResetMonitor implements IBinder.DeathRecipient {
564         private static final long WAKELOCK_TIMEOUT_MS = 2000;
565         private final IBiometricServiceLockoutResetCallback mCallback;
566         private final PowerManager.WakeLock mWakeLock;
567 
LockoutResetMonitor(IBiometricServiceLockoutResetCallback callback)568         public LockoutResetMonitor(IBiometricServiceLockoutResetCallback callback) {
569             mCallback = callback;
570             mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
571                     "lockout reset callback");
572             try {
573                 mCallback.asBinder().linkToDeath(LockoutResetMonitor.this, 0);
574             } catch (RemoteException e) {
575                 Slog.w(getTag(), "caught remote exception in linkToDeath", e);
576             }
577         }
578 
sendLockoutReset()579         public void sendLockoutReset() {
580             if (mCallback != null) {
581                 try {
582                     mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
583                     mCallback.onLockoutReset(getHalDeviceId(), new IRemoteCallback.Stub() {
584                         @Override
585                         public void sendResult(Bundle data) throws RemoteException {
586                             releaseWakelock();
587                         }
588                     });
589                 } catch (DeadObjectException e) {
590                     Slog.w(getTag(), "Death object while invoking onLockoutReset: ", e);
591                     mHandler.post(mRemoveCallbackRunnable);
592                 } catch (RemoteException e) {
593                     Slog.w(getTag(), "Failed to invoke onLockoutReset: ", e);
594                     releaseWakelock();
595                 }
596             }
597         }
598 
599         private final Runnable mRemoveCallbackRunnable = new Runnable() {
600             @Override
601             public void run() {
602                 releaseWakelock();
603                 removeLockoutResetCallback(LockoutResetMonitor.this);
604             }
605         };
606 
607         @Override
binderDied()608         public void binderDied() {
609             Slog.e(getTag(), "Lockout reset callback binder died");
610             mHandler.post(mRemoveCallbackRunnable);
611         }
612 
releaseWakelock()613         private void releaseWakelock() {
614             if (mWakeLock.isHeld()) {
615                 mWakeLock.release();
616             }
617         }
618     }
619 
620     /**
621      * Container for enumerated templates. Used to keep track when cleaning up unknown
622      * templates.
623      */
624     private final class UserTemplate {
625         final BiometricAuthenticator.Identifier mIdentifier;
626         final int mUserId;
UserTemplate(BiometricAuthenticator.Identifier identifier, int userId)627         UserTemplate(BiometricAuthenticator.Identifier identifier, int userId) {
628             this.mIdentifier = identifier;
629             this.mUserId = userId;
630         }
631     }
632 
633     /**
634      * Initializes the system service.
635      * <p>
636      * Subclasses must define a single argument constructor that accepts the context
637      * and passes it to super.
638      * </p>
639      *
640      * @param context The system server context.
641      */
BiometricServiceBase(Context context)642     public BiometricServiceBase(Context context) {
643         super(context);
644         mContext = context;
645         mStatusBarService = IStatusBarService.Stub.asInterface(
646                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
647         mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
648                 com.android.internal.R.string.config_keyguardComponent)).getPackageName();
649         mAppOps = context.getSystemService(AppOpsManager.class);
650         mActivityTaskManager = ((ActivityTaskManager) context.getSystemService(
651                 Context.ACTIVITY_TASK_SERVICE)).getService();
652         mPowerManager = mContext.getSystemService(PowerManager.class);
653         mUserManager = UserManager.get(mContext);
654         mMetricsLogger = new MetricsLogger();
655     }
656 
657     @Override
onStart()658     public void onStart() {
659         listenForUserSwitches();
660     }
661 
662     @Override
serviceDied(long cookie)663     public void serviceDied(long cookie) {
664         Slog.e(getTag(), "HAL died");
665         mMetricsLogger.count(getConstants().tagHalDied(), 1);
666         mHALDeathCount++;
667         mCurrentUserId = UserHandle.USER_NULL;
668 
669         // All client lifecycle must be managed on the handler.
670         mHandler.post(() -> {
671             handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
672                     0 /*vendorCode */);
673         });
674 
675         StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(),
676                 BiometricsProtoEnums.ISSUE_HAL_DEATH);
677     }
678 
getCurrentClient()679     protected ClientMonitor getCurrentClient() {
680         return mCurrentClient;
681     }
682 
getPendingClient()683     protected ClientMonitor getPendingClient() {
684         return mPendingClient;
685     }
686 
687     /**
688      * Callback handlers from the daemon. The caller must put this on a handler.
689      */
690 
handleAcquired(long deviceId, int acquiredInfo, int vendorCode)691     protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
692         ClientMonitor client = mCurrentClient;
693         if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
694             removeClient(client);
695         }
696         if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
697                 && client instanceof AuthenticationClient) {
698             // ignore enrollment acquisitions or acquisitions when we're locked out
699             mPerformanceStats.acquire++;
700         }
701     }
702 
handleAuthenticated(BiometricAuthenticator.Identifier identifier, ArrayList<Byte> token)703     protected void handleAuthenticated(BiometricAuthenticator.Identifier identifier,
704             ArrayList<Byte> token) {
705         ClientMonitor client = mCurrentClient;
706         final boolean authenticated = identifier.getBiometricId() != 0;
707 
708         if (client != null && client.onAuthenticated(identifier, authenticated, token)) {
709             removeClient(client);
710         }
711         if (authenticated) {
712             mPerformanceStats.accept++;
713         } else {
714             mPerformanceStats.reject++;
715         }
716     }
717 
handleEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)718     protected void handleEnrollResult(BiometricAuthenticator.Identifier identifier,
719             int remaining) {
720         ClientMonitor client = mCurrentClient;
721         if (client != null && client.onEnrollResult(identifier, remaining)) {
722             removeClient(client);
723             // When enrollment finishes, update this group's authenticator id, as the HAL has
724             // already generated a new authenticator id when the new biometric is enrolled.
725             if (identifier instanceof Fingerprint) {
726                 updateActiveGroup(((Fingerprint)identifier).getGroupId(), null);
727             }
728         }
729     }
730 
handleError(long deviceId, int error, int vendorCode)731     protected void handleError(long deviceId, int error, int vendorCode) {
732         final ClientMonitor client = mCurrentClient;
733 
734         if (DEBUG) Slog.v(getTag(), "handleError(client="
735                 + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
736 
737         if (client instanceof InternalRemovalClient
738                 || client instanceof InternalEnumerateClient) {
739             clearEnumerateState();
740         }
741 
742         if (client != null && client.onError(deviceId, error, vendorCode)) {
743             removeClient(client);
744         }
745 
746         if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
747             mHandler.removeCallbacks(mResetClientState);
748             if (mPendingClient != null) {
749                 if (DEBUG) Slog.v(getTag(), "start pending client " +
750                         mPendingClient.getOwnerString());
751                 startClient(mPendingClient, false);
752                 mPendingClient = null;
753             }
754         }
755     }
756 
handleRemoved(BiometricAuthenticator.Identifier identifier, final int remaining)757     protected void handleRemoved(BiometricAuthenticator.Identifier identifier,
758             final int remaining) {
759         if (DEBUG) Slog.w(getTag(), "Removed: fid=" + identifier.getBiometricId()
760                 + ", dev=" + identifier.getDeviceId()
761                 + ", rem=" + remaining);
762 
763         ClientMonitor client = mCurrentClient;
764         if (client != null && client.onRemoved(identifier, remaining)) {
765             removeClient(client);
766             // When the last biometric of a group is removed, update the authenticator id
767             int userId = mCurrentUserId;
768             if (identifier instanceof Fingerprint) {
769                 userId = ((Fingerprint) identifier).getGroupId();
770             }
771             if (!hasEnrolledBiometrics(userId)) {
772                 updateActiveGroup(userId, null);
773             }
774         }
775 
776         if (client instanceof InternalRemovalClient && !mUnknownHALTemplates.isEmpty()) {
777             startCleanupUnknownHALTemplates();
778         } else if (client instanceof InternalRemovalClient) {
779             clearEnumerateState();
780         }
781     }
782 
handleEnumerate(BiometricAuthenticator.Identifier identifier, int remaining)783     protected void handleEnumerate(BiometricAuthenticator.Identifier identifier, int remaining) {
784         ClientMonitor client = getCurrentClient();
785 
786         client.onEnumerationResult(identifier, remaining);
787 
788         // All templates in the HAL for this user were enumerated
789         if (remaining == 0) {
790             if (client instanceof InternalEnumerateClient) {
791                 List<BiometricAuthenticator.Identifier> unknownHALTemplates =
792                         ((InternalEnumerateClient) client).getUnknownHALTemplates();
793 
794                 if (!unknownHALTemplates.isEmpty()) {
795                     Slog.w(getTag(), "Adding " + unknownHALTemplates.size()
796                             + " templates for deletion");
797                 }
798                 for (int i = 0; i < unknownHALTemplates.size(); i++) {
799                     mUnknownHALTemplates.add(new UserTemplate(unknownHALTemplates.get(i),
800                             client.getTargetUserId()));
801                 }
802                 removeClient(client);
803                 startCleanupUnknownHALTemplates();
804             } else {
805                 removeClient(client);
806             }
807         }
808     }
809 
810     /**
811      * Calls from the Manager. These are still on the calling binder's thread.
812      */
813 
enrollInternal(EnrollClientImpl client, int userId)814     protected void enrollInternal(EnrollClientImpl client, int userId) {
815         if (hasReachedEnrollmentLimit(userId)) {
816             return;
817         }
818 
819         // Group ID is arbitrarily set to parent profile user ID. It just represents
820         // the default biometrics for the user.
821         if (!isCurrentUserOrProfile(userId)) {
822             return;
823         }
824 
825         mHandler.post(() -> {
826             startClient(client, true /* initiatedByClient */);
827         });
828     }
829 
cancelEnrollmentInternal(IBinder token)830     protected void cancelEnrollmentInternal(IBinder token) {
831         mHandler.post(() -> {
832             ClientMonitor client = mCurrentClient;
833             if (client instanceof EnrollClient && client.getToken() == token) {
834                 if (DEBUG) Slog.v(getTag(), "Cancelling enrollment");
835                 client.stop(client.getToken() == token);
836             }
837         });
838     }
839 
authenticateInternal(AuthenticationClientImpl client, long opId, String opPackageName)840     protected void authenticateInternal(AuthenticationClientImpl client, long opId,
841             String opPackageName) {
842         final int callingUid = Binder.getCallingUid();
843         final int callingPid = Binder.getCallingPid();
844         final int callingUserId = UserHandle.getCallingUserId();
845         authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId);
846     }
847 
authenticateInternal(AuthenticationClientImpl client, long opId, String opPackageName, int callingUid, int callingPid, int callingUserId)848     protected void authenticateInternal(AuthenticationClientImpl client, long opId,
849             String opPackageName, int callingUid, int callingPid, int callingUserId) {
850         if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
851                 callingUserId)) {
852             if (DEBUG) Slog.v(getTag(), "authenticate(): reject " + opPackageName);
853             return;
854         }
855 
856         mHandler.post(() -> {
857             mMetricsLogger.histogram(getConstants().tagAuthToken(), opId != 0L ? 1 : 0);
858 
859             // Get performance stats object for this user.
860             HashMap<Integer, PerformanceStats> pmap
861                     = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
862             PerformanceStats stats = pmap.get(mCurrentUserId);
863             if (stats == null) {
864                 stats = new PerformanceStats();
865                 pmap.put(mCurrentUserId, stats);
866             }
867             mPerformanceStats = stats;
868             mIsCrypto = (opId != 0);
869 
870             startAuthentication(client, opPackageName);
871         });
872     }
873 
cancelAuthenticationInternal(final IBinder token, final String opPackageName)874     protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName) {
875         final int callingUid = Binder.getCallingUid();
876         final int callingPid = Binder.getCallingPid();
877         final int callingUserId = UserHandle.getCallingUserId();
878         cancelAuthenticationInternal(token, opPackageName, callingUid, callingPid, callingUserId,
879                 true /* fromClient */);
880     }
881 
cancelAuthenticationInternal(final IBinder token, final String opPackageName, int callingUid, int callingPid, int callingUserId, boolean fromClient)882     protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName,
883             int callingUid, int callingPid, int callingUserId, boolean fromClient) {
884         if (fromClient) {
885             // Only check this if cancel was called from the client (app). If cancel was called
886             // from BiometricService, it means the dialog was dismissed due to user interaction.
887             if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
888                     callingUserId)) {
889                 if (DEBUG) Slog.v(getTag(), "cancelAuthentication(): reject " + opPackageName);
890                 return;
891             }
892         }
893 
894         mHandler.post(() -> {
895             ClientMonitor client = mCurrentClient;
896             if (client instanceof AuthenticationClient) {
897                 if (client.getToken() == token || !fromClient) {
898                     if (DEBUG) Slog.v(getTag(), "Stopping client " + client.getOwnerString()
899                             + ", fromClient: " + fromClient);
900                     // If cancel was from BiometricService, it means the dialog was dismissed
901                     // and authentication should be canceled.
902                     client.stop(client.getToken() == token);
903                 } else {
904                     if (DEBUG) Slog.v(getTag(), "Can't stop client " + client.getOwnerString()
905                             + " since tokens don't match. fromClient: " + fromClient);
906                 }
907             } else if (client != null) {
908                 if (DEBUG) Slog.v(getTag(), "Can't cancel non-authenticating client "
909                         + client.getOwnerString());
910             }
911         });
912     }
913 
setActiveUserInternal(int userId)914     protected void setActiveUserInternal(int userId) {
915         mHandler.post(() -> {
916             if (DEBUG) {
917                 Slog.d(getTag(), "setActiveUser(" + userId + ")");
918             }
919             updateActiveGroup(userId, null /* clientPackage */);
920         });
921     }
922 
removeInternal(RemovalClient client)923     protected void removeInternal(RemovalClient client) {
924         mHandler.post(() -> {
925             startClient(client, true /* initiatedByClient */);
926         });
927     }
928 
enumerateInternal(EnumerateClient client)929     protected void enumerateInternal(EnumerateClient client) {
930         mHandler.post(() -> {
931             startClient(client, true /* initiatedByClient */);
932         });
933     }
934 
935     // Should be done on a handler thread - not on the Binder's thread.
startAuthentication(AuthenticationClientImpl client, String opPackageName)936     private void startAuthentication(AuthenticationClientImpl client, String opPackageName) {
937         if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");
938 
939         int lockoutMode = getLockoutMode();
940         if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
941             Slog.v(getTag(), "In lockout mode(" + lockoutMode + ") ; disallowing authentication");
942             int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
943                     BiometricConstants.BIOMETRIC_ERROR_LOCKOUT :
944                     BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
945             if (!client.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */)) {
946                 Slog.w(getTag(), "Cannot send permanent lockout message to client");
947             }
948             return;
949         }
950         startClient(client, true /* initiatedByClient */);
951     }
952 
addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback)953     protected void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback) {
954         mHandler.post(() -> {
955            final LockoutResetMonitor monitor = new LockoutResetMonitor(callback);
956            if (!mLockoutMonitors.contains(monitor)) {
957                mLockoutMonitors.add(monitor);
958            }
959         });
960     }
961 
962     /**
963      * Helper methods.
964      */
965 
966     /**
967      * @param opPackageName name of package for caller
968      * @param requireForeground only allow this call while app is in the foreground
969      * @return true if caller can use the biometric API
970      */
canUseBiometric(String opPackageName, boolean requireForeground, int uid, int pid, int userId)971     protected boolean canUseBiometric(String opPackageName, boolean requireForeground, int uid,
972             int pid, int userId) {
973         checkUseBiometricPermission();
974 
975 
976         if (Binder.getCallingUid() == Process.SYSTEM_UID) {
977             return true; // System process (BiometricService, etc) is always allowed
978         }
979         if (isKeyguard(opPackageName)) {
980             return true; // Keyguard is always allowed
981         }
982         if (!isCurrentUserOrProfile(userId)) {
983             Slog.w(getTag(), "Rejecting " + opPackageName + "; not a current user or profile");
984             return false;
985         }
986         if (!checkAppOps(uid, opPackageName)) {
987             Slog.w(getTag(), "Rejecting " + opPackageName + "; permission denied");
988             return false;
989         }
990 
991         if (requireForeground && !(isForegroundActivity(uid, pid) || isCurrentClient(
992                 opPackageName))) {
993             Slog.w(getTag(), "Rejecting " + opPackageName + "; not in foreground");
994             return false;
995         }
996         return true;
997     }
998 
999     /**
1000      * @param opPackageName package of the caller
1001      * @return true if this is the same client currently using the biometric
1002      */
isCurrentClient(String opPackageName)1003     private boolean isCurrentClient(String opPackageName) {
1004         return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
1005     }
1006 
1007     /**
1008      * @return true if this is keyguard package
1009      */
isKeyguard(String clientPackage)1010     private boolean isKeyguard(String clientPackage) {
1011         return mKeyguardPackage.equals(clientPackage);
1012     }
1013 
isForegroundActivity(int uid, int pid)1014     private boolean isForegroundActivity(int uid, int pid) {
1015         try {
1016             List<ActivityManager.RunningAppProcessInfo> procs =
1017                     ActivityManager.getService().getRunningAppProcesses();
1018             int N = procs.size();
1019             for (int i = 0; i < N; i++) {
1020                 ActivityManager.RunningAppProcessInfo proc = procs.get(i);
1021                 if (proc.pid == pid && proc.uid == uid
1022                         && proc.importance <= IMPORTANCE_FOREGROUND_SERVICE) {
1023                     return true;
1024                 }
1025             }
1026         } catch (RemoteException e) {
1027             Slog.w(getTag(), "am.getRunningAppProcesses() failed");
1028         }
1029         return false;
1030     }
1031 
1032     /**
1033      * Calls the HAL to switch states to the new task. If there's already a current task,
1034      * it calls cancel() and sets mPendingClient to begin when the current task finishes
1035      * ({@link BiometricConstants#BIOMETRIC_ERROR_CANCELED}).
1036      *
1037      * @param newClient the new client that wants to connect
1038      * @param initiatedByClient true for authenticate, remove and enroll
1039      */
startClient(ClientMonitor newClient, boolean initiatedByClient)1040     private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
1041         ClientMonitor currentClient = mCurrentClient;
1042         if (currentClient != null) {
1043             if (DEBUG) Slog.v(getTag(), "request stop current client " +
1044                     currentClient.getOwnerString());
1045             // This check only matters for FingerprintService, since enumerate may call back
1046             // multiple times.
1047             if (currentClient instanceof InternalEnumerateClient
1048                     || currentClient instanceof InternalRemovalClient) {
1049                 // This condition means we're currently running internal diagnostics to
1050                 // remove extra templates in the hardware and/or the software
1051                 // TODO: design an escape hatch in case client never finishes
1052                 if (newClient != null) {
1053                     Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
1054                             + newClient.getClass().getSuperclass().getSimpleName()
1055                             + "(" + newClient.getOwnerString() + ")"
1056                             + ", initiatedByClient = " + initiatedByClient);
1057                 }
1058             } else {
1059                 currentClient.stop(initiatedByClient);
1060 
1061                 // Only post the reset runnable for non-cleanup clients. Cleanup clients should
1062                 // never be forcibly stopped since they ensure synchronization between HAL and
1063                 // framework. Thus, we should instead just start the pending client once cleanup
1064                 // finishes instead of using the reset runnable.
1065                 mHandler.removeCallbacks(mResetClientState);
1066                 mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
1067             }
1068             mPendingClient = newClient;
1069         } else if (newClient != null) {
1070             // For BiometricPrompt clients, do not start until
1071             // <Biometric>Service#startPreparedClient is called. BiometricService waits until all
1072             // modalities are ready before initiating authentication.
1073             if (newClient instanceof AuthenticationClient) {
1074                 AuthenticationClient client = (AuthenticationClient) newClient;
1075                 if (client.isBiometricPrompt()) {
1076                     if (DEBUG) Slog.v(getTag(), "Returning cookie: " + client.getCookie());
1077                     mCurrentClient = newClient;
1078                     if (mBiometricService == null) {
1079                         mBiometricService = IBiometricService.Stub.asInterface(
1080                                 ServiceManager.getService(Context.BIOMETRIC_SERVICE));
1081                     }
1082                     try {
1083                         mBiometricService.onReadyForAuthentication(client.getCookie(),
1084                                 client.getRequireConfirmation(), client.getTargetUserId());
1085                     } catch (RemoteException e) {
1086                         Slog.e(getTag(), "Remote exception", e);
1087                     }
1088                     return;
1089                 }
1090             }
1091 
1092             // We are not a BiometricPrompt client, start the client immediately
1093             mCurrentClient = newClient;
1094             startCurrentClient(mCurrentClient.getCookie());
1095         }
1096     }
1097 
startCurrentClient(int cookie)1098     protected void startCurrentClient(int cookie) {
1099         if (mCurrentClient == null) {
1100             Slog.e(getTag(), "Trying to start null client!");
1101             return;
1102         }
1103         if (DEBUG) Slog.v(getTag(), "starting client "
1104                 + mCurrentClient.getClass().getSuperclass().getSimpleName()
1105                 + "(" + mCurrentClient.getOwnerString() + ")"
1106                 + " targetUserId: " + mCurrentClient.getTargetUserId()
1107                 + " currentUserId: " + mCurrentUserId
1108                 + " cookie: " + cookie + "/" + mCurrentClient.getCookie());
1109         if (cookie != mCurrentClient.getCookie()) {
1110             Slog.e(getTag(), "Mismatched cookie");
1111             return;
1112         }
1113         notifyClientActiveCallbacks(true);
1114         mCurrentClient.start();
1115     }
1116 
removeClient(ClientMonitor client)1117     protected void removeClient(ClientMonitor client) {
1118         if (client != null) {
1119             client.destroy();
1120             if (client != mCurrentClient && mCurrentClient != null) {
1121                 Slog.w(getTag(), "Unexpected client: " + client.getOwnerString() + "expected: "
1122                         + mCurrentClient.getOwnerString());
1123             }
1124         }
1125         if (mCurrentClient != null) {
1126             if (DEBUG) Slog.v(getTag(), "Done with client: " + client.getOwnerString());
1127             mCurrentClient = null;
1128         }
1129         if (mPendingClient == null) {
1130             notifyClientActiveCallbacks(false);
1131         }
1132     }
1133 
1134     /**
1135      * Populates existing authenticator ids. To be used only during the start of the service.
1136      */
loadAuthenticatorIds()1137     protected void loadAuthenticatorIds() {
1138         // This operation can be expensive, so keep track of the elapsed time. Might need to move to
1139         // background if it takes too long.
1140         long t = System.currentTimeMillis();
1141         mAuthenticatorIds.clear();
1142         for (UserInfo user : UserManager.get(getContext()).getUsers(true /* excludeDying */)) {
1143             int userId = getUserOrWorkProfileId(null, user.id);
1144             if (!mAuthenticatorIds.containsKey(userId)) {
1145                 updateActiveGroup(userId, null);
1146             }
1147         }
1148 
1149         t = System.currentTimeMillis() - t;
1150         if (t > 1000) {
1151             Slog.w(getTag(), "loadAuthenticatorIds() taking too long: " + t + "ms");
1152         }
1153     }
1154 
1155     /**
1156      * @param clientPackage the package of the caller
1157      * @return the profile id
1158      */
getUserOrWorkProfileId(String clientPackage, int userId)1159     protected int getUserOrWorkProfileId(String clientPackage, int userId) {
1160         if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
1161             return userId;
1162         }
1163         return getEffectiveUserId(userId);
1164     }
1165 
isRestricted()1166     protected boolean isRestricted() {
1167         // Only give privileged apps (like Settings) access to biometric info
1168         final boolean restricted = !hasPermission(getManageBiometricPermission());
1169         return restricted;
1170     }
1171 
hasPermission(String permission)1172     protected boolean hasPermission(String permission) {
1173         return getContext().checkCallingOrSelfPermission(permission)
1174                 == PackageManager.PERMISSION_GRANTED;
1175     }
1176 
checkPermission(String permission)1177     protected void checkPermission(String permission) {
1178         getContext().enforceCallingOrSelfPermission(permission,
1179                 "Must have " + permission + " permission.");
1180     }
1181 
isCurrentUserOrProfile(int userId)1182     protected boolean isCurrentUserOrProfile(int userId) {
1183         UserManager um = UserManager.get(mContext);
1184         if (um == null) {
1185             Slog.e(getTag(), "Unable to acquire UserManager");
1186             return false;
1187         }
1188 
1189         final long token = Binder.clearCallingIdentity();
1190         try {
1191             // Allow current user or profiles of the current user...
1192             for (int profileId : um.getEnabledProfileIds(ActivityManager.getCurrentUser())) {
1193                 if (profileId == userId) {
1194                     return true;
1195                 }
1196             }
1197         } finally {
1198             Binder.restoreCallingIdentity(token);
1199         }
1200 
1201         return false;
1202     }
1203 
1204     /***
1205      * @param opPackageName the name of the calling package
1206      * @return authenticator id for the calling user
1207      */
getAuthenticatorId(String opPackageName)1208     protected long getAuthenticatorId(String opPackageName) {
1209         final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
1210         return mAuthenticatorIds.getOrDefault(userId, 0L);
1211     }
1212 
1213     /**
1214      * This method should be called upon connection to the daemon, and when user switches.
1215      * @param userId
1216      */
doTemplateCleanupForUser(int userId)1217     protected void doTemplateCleanupForUser(int userId) {
1218         if (CLEANUP_UNKNOWN_TEMPLATES) {
1219             enumerateUser(userId);
1220         }
1221     }
1222 
clearEnumerateState()1223     private void clearEnumerateState() {
1224         if (DEBUG) Slog.v(getTag(), "clearEnumerateState()");
1225         mUnknownHALTemplates.clear();
1226     }
1227 
1228     /**
1229      * Remove unknown templates from HAL
1230      */
startCleanupUnknownHALTemplates()1231     private void startCleanupUnknownHALTemplates() {
1232         if (!mUnknownHALTemplates.isEmpty()) {
1233             UserTemplate template = mUnknownHALTemplates.get(0);
1234             mUnknownHALTemplates.remove(template);
1235             boolean restricted = !hasPermission(getManageBiometricPermission());
1236             InternalRemovalClient client = new InternalRemovalClient(getContext(),
1237                     getDaemonWrapper(), mHalDeviceId, mToken, null /* listener */,
1238                     template.mIdentifier.getBiometricId(), 0 /* groupId */, template.mUserId,
1239                     restricted, getContext().getPackageName());
1240             removeInternal(client);
1241             StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
1242                     statsModality(),
1243                     BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL);
1244         } else {
1245             clearEnumerateState();
1246             if (mPendingClient != null) {
1247                 Slog.d(getTag(), "Enumerate finished, starting pending client");
1248                 startClient(mPendingClient, false /* initiatedByClient */);
1249                 mPendingClient = null;
1250             }
1251         }
1252     }
1253 
enumerateUser(int userId)1254     private void enumerateUser(int userId) {
1255         if (DEBUG) Slog.v(getTag(), "Enumerating user(" + userId + ")");
1256 
1257         final boolean restricted = !hasPermission(getManageBiometricPermission());
1258         final List<? extends BiometricAuthenticator.Identifier> enrolledList =
1259                 getEnrolledTemplates(userId);
1260 
1261         InternalEnumerateClient client = new InternalEnumerateClient(getContext(),
1262                 getDaemonWrapper(), mHalDeviceId, mToken, null /* serviceListener */, userId,
1263                 userId, restricted, getContext().getOpPackageName(), enrolledList,
1264                 getBiometricUtils());
1265         enumerateInternal(client);
1266     }
1267 
1268     /**
1269      * This method is called when the user switches. Implementations should probably notify the
1270      * HAL.
1271      */
handleUserSwitching(int userId)1272     protected void handleUserSwitching(int userId) {
1273         if (getCurrentClient() instanceof InternalRemovalClient
1274                 || getCurrentClient() instanceof InternalEnumerateClient) {
1275             Slog.w(getTag(), "User switched while performing cleanup");
1276         }
1277         updateActiveGroup(userId, null);
1278         doTemplateCleanupForUser(userId);
1279     }
1280 
notifyLockoutResetMonitors()1281     protected void notifyLockoutResetMonitors() {
1282         for (int i = 0; i < mLockoutMonitors.size(); i++) {
1283             mLockoutMonitors.get(i).sendLockoutReset();
1284         }
1285     }
1286 
userActivity()1287     private void userActivity() {
1288         long now = SystemClock.uptimeMillis();
1289         mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
1290     }
1291 
1292     /**
1293      * @param userId
1294      * @return true if this is a work profile
1295      */
isWorkProfile(int userId)1296     private boolean isWorkProfile(int userId) {
1297         UserInfo userInfo = null;
1298         final long token = Binder.clearCallingIdentity();
1299         try {
1300             userInfo = mUserManager.getUserInfo(userId);
1301         } finally {
1302             Binder.restoreCallingIdentity(token);
1303         }
1304         return userInfo != null && userInfo.isManagedProfile();
1305     }
1306 
1307 
getEffectiveUserId(int userId)1308     private int getEffectiveUserId(int userId) {
1309         UserManager um = UserManager.get(mContext);
1310         if (um != null) {
1311             final long callingIdentity = Binder.clearCallingIdentity();
1312             userId = um.getCredentialOwnerProfile(userId);
1313             Binder.restoreCallingIdentity(callingIdentity);
1314         } else {
1315             Slog.e(getTag(), "Unable to acquire UserManager");
1316         }
1317         return userId;
1318     }
1319 
1320 
listenForUserSwitches()1321     private void listenForUserSwitches() {
1322         try {
1323             ActivityManager.getService().registerUserSwitchObserver(
1324                     new SynchronousUserSwitchObserver() {
1325                         @Override
1326                         public void onUserSwitching(int newUserId) throws RemoteException {
1327                             mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
1328                                     .sendToTarget();
1329                         }
1330                     }, getTag());
1331         } catch (RemoteException e) {
1332             Slog.w(getTag(), "Failed to listen for user switching event" ,e);
1333         }
1334     }
1335 
removeLockoutResetCallback( LockoutResetMonitor monitor)1336     private void removeLockoutResetCallback(
1337             LockoutResetMonitor monitor) {
1338         mLockoutMonitors.remove(monitor);
1339     }
1340 }
1341