• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 
20 // TODO(b/141025588): Create separate internal and external permissions for AuthService.
21 // TODO(b/141025588): Get rid of the USE_FINGERPRINT permission.
22 
23 import static android.Manifest.permission.SET_BIOMETRIC_DIALOG_ADVANCED;
24 import static android.Manifest.permission.TEST_BIOMETRIC;
25 import static android.Manifest.permission.USE_BIOMETRIC;
26 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
27 import static android.Manifest.permission.USE_FINGERPRINT;
28 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS;
29 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
30 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
31 import static android.hardware.biometrics.BiometricManager.Authenticators;
32 
33 import android.annotation.NonNull;
34 import android.app.AppOpsManager;
35 import android.content.Context;
36 import android.content.pm.PackageManager;
37 import android.hardware.biometrics.AuthenticationStateListener;
38 import android.hardware.biometrics.BiometricAuthenticator;
39 import android.hardware.biometrics.BiometricManager;
40 import android.hardware.biometrics.ComponentInfoInternal;
41 import android.hardware.biometrics.IAuthService;
42 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
43 import android.hardware.biometrics.IBiometricService;
44 import android.hardware.biometrics.IBiometricServiceReceiver;
45 import android.hardware.biometrics.IInvalidationCallback;
46 import android.hardware.biometrics.ITestSession;
47 import android.hardware.biometrics.ITestSessionCallback;
48 import android.hardware.biometrics.PromptInfo;
49 import android.hardware.biometrics.SensorLocationInternal;
50 import android.hardware.biometrics.SensorPropertiesInternal;
51 import android.hardware.face.FaceSensorConfigurations;
52 import android.hardware.face.FaceSensorProperties;
53 import android.hardware.face.FaceSensorPropertiesInternal;
54 import android.hardware.face.IFaceService;
55 import android.hardware.fingerprint.FingerprintSensorConfigurations;
56 import android.hardware.fingerprint.FingerprintSensorProperties;
57 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
58 import android.hardware.fingerprint.IFingerprintService;
59 import android.hardware.iris.IIrisService;
60 import android.os.Binder;
61 import android.os.Build;
62 import android.os.IBinder;
63 import android.os.RemoteException;
64 import android.os.ServiceManager;
65 import android.os.SystemProperties;
66 import android.os.UserHandle;
67 import android.provider.Settings;
68 import android.util.Slog;
69 
70 import com.android.internal.R;
71 import com.android.internal.annotations.VisibleForTesting;
72 import com.android.internal.util.ArrayUtils;
73 import com.android.server.SystemService;
74 import com.android.server.biometrics.sensors.face.FaceService;
75 import com.android.server.biometrics.sensors.fingerprint.FingerprintService;
76 import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
77 
78 import java.util.ArrayList;
79 import java.util.Arrays;
80 import java.util.List;
81 
82 /**
83  * System service that provides an interface for authenticating with biometrics and
84  * PIN/pattern/password to BiometricPrompt and lock screen.
85  */
86 public class AuthService extends SystemService {
87     private static final String TAG = "AuthService";
88     private static final String SETTING_HIDL_DISABLED =
89             "com.android.server.biometrics.AuthService.hidlDisabled";
90     private static final int DEFAULT_HIDL_DISABLED = 0;
91     private static final String SYSPROP_FIRST_API_LEVEL = "ro.board.first_api_level";
92     private static final String SYSPROP_API_LEVEL = "ro.board.api_level";
93 
94     private final Injector mInjector;
95 
96     private IBiometricService mBiometricService;
97     @VisibleForTesting
98     final IAuthService.Stub mImpl;
99 
100     /**
101      * Class for injecting dependencies into AuthService.
102      * TODO(b/141025588): Replace with a dependency injection framework (e.g. Guice, Dagger).
103      */
104     @VisibleForTesting
105     public static class Injector {
106 
107         /**
108          * Allows to mock BiometricService for testing.
109          */
110         @VisibleForTesting
getBiometricService()111         public IBiometricService getBiometricService() {
112             return IBiometricService.Stub.asInterface(
113                     ServiceManager.getService(Context.BIOMETRIC_SERVICE));
114         }
115 
116         /**
117          * Allows to stub publishBinderService(...) for testing.
118          */
119         @VisibleForTesting
publishBinderService(AuthService service, IAuthService.Stub impl)120         public void publishBinderService(AuthService service, IAuthService.Stub impl) {
121             service.publishBinderService(Context.AUTH_SERVICE, impl);
122         }
123 
124         /**
125          * Allows to test with various device sensor configurations.
126          */
127         @VisibleForTesting
getConfiguration(Context context)128         public String[] getConfiguration(Context context) {
129             return context.getResources().getStringArray(R.array.config_biometric_sensors);
130         }
131 
132         /**
133          * Allows to test with various device sensor configurations.
134          */
135         @VisibleForTesting
getFingerprintConfiguration(Context context)136         public String[] getFingerprintConfiguration(Context context) {
137             return getConfiguration(context);
138         }
139 
140         /**
141          * Allows to test with various device sensor configurations.
142          */
143         @VisibleForTesting
getFaceConfiguration(Context context)144         public String[] getFaceConfiguration(Context context) {
145             return getConfiguration(context);
146         }
147 
148         /**
149          * Allows to test with various device sensor configurations.
150          */
151         @VisibleForTesting
getIrisConfiguration(Context context)152         public String[] getIrisConfiguration(Context context) {
153             return getConfiguration(context);
154         }
155 
156         /**
157          * Allows us to mock FingerprintService for testing
158          */
159         @VisibleForTesting
getFingerprintService()160         public IFingerprintService getFingerprintService() {
161             return IFingerprintService.Stub.asInterface(
162                     ServiceManager.getService(Context.FINGERPRINT_SERVICE));
163         }
164 
165         /**
166          * Allows us to mock FaceService for testing
167          */
168         @VisibleForTesting
getFaceService()169         public IFaceService getFaceService() {
170             return IFaceService.Stub.asInterface(
171                     ServiceManager.getService(Context.FACE_SERVICE));
172         }
173 
174         /**
175          * Allows us to mock IrisService for testing
176          */
177         @VisibleForTesting
getIrisService()178         public IIrisService getIrisService() {
179             return IIrisService.Stub.asInterface(
180                     ServiceManager.getService(Context.IRIS_SERVICE));
181         }
182 
183         @VisibleForTesting
getAppOps(Context context)184         public AppOpsManager getAppOps(Context context) {
185             return context.getSystemService(AppOpsManager.class);
186         }
187 
188         /**
189          * Allows to ignore HIDL HALs on debug builds based on a secure setting.
190          */
191         @VisibleForTesting
isHidlDisabled(Context context)192         public boolean isHidlDisabled(Context context) {
193             if (Build.IS_ENG || Build.IS_USERDEBUG) {
194                 return Settings.Secure.getIntForUser(context.getContentResolver(),
195                         SETTING_HIDL_DISABLED, DEFAULT_HIDL_DISABLED, UserHandle.USER_CURRENT) == 1;
196             }
197             return false;
198         }
199 
200         /**
201          * Allows to test with various fingerprint aidl instances.
202          */
203         @VisibleForTesting
getFingerprintAidlInstances()204         public String[] getFingerprintAidlInstances() {
205             return FingerprintService.getDeclaredInstances();
206         }
207 
208         /**
209          * Allows to test with various face aidl instances.
210          */
211         @VisibleForTesting
getFaceAidlInstances()212         public String[] getFaceAidlInstances() {
213             return FaceService.getDeclaredInstances();
214         }
215 
216         /**
217          * Allows to test with handlers.
218          */
getBiometricHandlerProvider()219         public BiometricHandlerProvider getBiometricHandlerProvider() {
220             return BiometricHandlerProvider.getInstance();
221         }
222     }
223 
224     private final class AuthServiceImpl extends IAuthService.Stub {
225         @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
226         @Override
createTestSession(int sensorId, @NonNull ITestSessionCallback callback, @NonNull String opPackageName)227         public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
228                 @NonNull String opPackageName) throws RemoteException {
229 
230             super.createTestSession_enforcePermission();
231 
232             final long identity = Binder.clearCallingIdentity();
233             try {
234                 return mInjector.getBiometricService()
235                         .createTestSession(sensorId, callback, opPackageName);
236             } finally {
237                 Binder.restoreCallingIdentity(identity);
238             }
239         }
240 
241         @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
242         @Override
getSensorProperties(String opPackageName)243         public List<SensorPropertiesInternal> getSensorProperties(String opPackageName)
244                 throws RemoteException {
245 
246             super.getSensorProperties_enforcePermission();
247 
248             final long identity = Binder.clearCallingIdentity();
249             try {
250                 // Get the result from BiometricService, since it is the source of truth for all
251                 // biometric sensors.
252                 return mInjector.getBiometricService().getSensorProperties(opPackageName);
253             } finally {
254                 Binder.restoreCallingIdentity(identity);
255             }
256         }
257 
258         @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
259         @Override
getUiPackage()260         public String getUiPackage() {
261 
262             super.getUiPackage_enforcePermission();
263 
264             return getContext().getResources()
265                     .getString(R.string.config_biometric_prompt_ui_package);
266         }
267 
268         @Override
authenticate(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo)269         public long authenticate(IBinder token, long sessionId, int userId,
270                 IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo)
271                 throws RemoteException {
272             // Only allow internal clients to authenticate with a different userId.
273             final int callingUserId = UserHandle.getCallingUserId();
274             final int callingUid = Binder.getCallingUid();
275             final int callingPid = Binder.getCallingPid();
276             if (userId == callingUserId) {
277                 checkPermission();
278             } else {
279                 Slog.w(TAG, "User " + callingUserId + " is requesting authentication of userid: "
280                         + userId);
281                 checkInternalPermission();
282             }
283 
284             if (!checkAppOps(callingUid, opPackageName, "authenticate()")) {
285                 authenticateFastFail("Denied by app ops: " + opPackageName, receiver);
286                 return -1;
287             }
288 
289             if (token == null || receiver == null || opPackageName == null || promptInfo == null) {
290                 authenticateFastFail(
291                         "Unable to authenticate, one or more null arguments", receiver);
292                 return -1;
293             }
294 
295             if (!Utils.isForeground(callingUid, callingPid)) {
296                 authenticateFastFail("Caller is not foreground: " + opPackageName, receiver);
297                 return -1;
298             }
299 
300             if (promptInfo.requiresTestOrInternalPermission()) {
301                 if (getContext().checkCallingOrSelfPermission(TEST_BIOMETRIC)
302                         != PackageManager.PERMISSION_GRANTED) {
303                     checkInternalPermission();
304                 }
305             }
306 
307             // Only allow internal clients to enable non-public options.
308             if (promptInfo.requiresInternalPermission()) {
309                 checkInternalPermission();
310             }
311             if (promptInfo.requiresAdvancedPermission()) {
312                 checkBiometricAdvancedPermission();
313             }
314 
315             final long identity = Binder.clearCallingIdentity();
316             try {
317                 VirtualDeviceManagerInternal vdm = getLocalService(
318                         VirtualDeviceManagerInternal.class);
319                 if (vdm != null) {
320                     vdm.onAuthenticationPrompt(callingUid);
321                 }
322                 return mBiometricService.authenticate(
323                         token, sessionId, userId, receiver, opPackageName, promptInfo);
324             } finally {
325                 Binder.restoreCallingIdentity(identity);
326             }
327         }
328 
authenticateFastFail(String message, IBiometricServiceReceiver receiver)329         private void authenticateFastFail(String message, IBiometricServiceReceiver receiver) {
330             // notify caller in cases where authentication is aborted before calling into
331             // IBiometricService without raising an exception
332             Slog.e(TAG, "authenticateFastFail: " + message);
333             try {
334                 receiver.onError(TYPE_NONE, BIOMETRIC_ERROR_CANCELED, 0 /*vendorCode */);
335             } catch (RemoteException e) {
336                 Slog.e(TAG, "authenticateFastFail failed to notify caller", e);
337             }
338         }
339 
340         @Override
cancelAuthentication(IBinder token, String opPackageName, long requestId)341         public void cancelAuthentication(IBinder token, String opPackageName, long requestId)
342                 throws RemoteException {
343             checkPermission();
344 
345             if (token == null || opPackageName == null) {
346                 Slog.e(TAG, "Unable to cancel authentication, one or more null arguments");
347                 return;
348             }
349 
350             final long identity = Binder.clearCallingIdentity();
351             try {
352                 mBiometricService.cancelAuthentication(token, opPackageName, requestId);
353             } finally {
354                 Binder.restoreCallingIdentity(identity);
355             }
356         }
357 
358         @Override
canAuthenticate(String opPackageName, int userId, @Authenticators.Types int authenticators)359         public int canAuthenticate(String opPackageName, int userId,
360                 @Authenticators.Types int authenticators) throws RemoteException {
361 
362             // Only allow internal clients to call canAuthenticate with a different userId.
363             final int callingUserId = UserHandle.getCallingUserId();
364 
365             if (userId != callingUserId) {
366                 checkInternalPermission();
367             } else {
368                 checkPermission();
369             }
370 
371             final long identity = Binder.clearCallingIdentity();
372             try {
373                 final int result = mBiometricService.canAuthenticate(
374                         opPackageName, userId, callingUserId, authenticators);
375                 Slog.d(TAG, "canAuthenticate"
376                         + ", userId: " + userId
377                         + ", callingUserId: " + callingUserId
378                         + ", authenticators: " + authenticators
379                         + ", result: " + result);
380                 return result;
381             } finally {
382                 Binder.restoreCallingIdentity(identity);
383             }
384         }
385 
386         @Override
getLastAuthenticationTime(int userId, @Authenticators.Types int authenticators)387         public long getLastAuthenticationTime(int userId,
388                 @Authenticators.Types int authenticators) throws RemoteException {
389             // Only allow internal clients to call getLastAuthenticationTime with a different
390             // userId.
391             final int callingUserId = UserHandle.getCallingUserId();
392 
393             if (userId != callingUserId) {
394                 checkInternalPermission();
395             } else {
396                 checkPermission();
397             }
398 
399             final long identity = Binder.clearCallingIdentity();
400             try {
401                 return mBiometricService.getLastAuthenticationTime(userId, authenticators);
402             } finally {
403                 Binder.restoreCallingIdentity(identity);
404             }
405         }
406 
407         @Override
hasEnrolledBiometrics(int userId, String opPackageName)408         public boolean hasEnrolledBiometrics(int userId, String opPackageName)
409                 throws RemoteException {
410             checkInternalPermission();
411             final long identity = Binder.clearCallingIdentity();
412             try {
413                 return mBiometricService.hasEnrolledBiometrics(userId, opPackageName);
414             } finally {
415                 Binder.restoreCallingIdentity(identity);
416             }
417         }
418 
419         @Override
registerEnabledOnKeyguardCallback( IBiometricEnabledOnKeyguardCallback callback)420         public void registerEnabledOnKeyguardCallback(
421                 IBiometricEnabledOnKeyguardCallback callback) throws RemoteException {
422             checkInternalPermission();
423             final long identity = Binder.clearCallingIdentity();
424             try {
425                 mBiometricService.registerEnabledOnKeyguardCallback(callback);
426             } finally {
427                 Binder.restoreCallingIdentity(identity);
428             }
429         }
430 
431         @Override
registerAuthenticationStateListener(AuthenticationStateListener listener)432         public void registerAuthenticationStateListener(AuthenticationStateListener listener)
433                 throws RemoteException {
434             checkInternalPermission();
435             final IFingerprintService fingerprintService = mInjector.getFingerprintService();
436             if (fingerprintService != null) {
437                 fingerprintService.registerAuthenticationStateListener(listener);
438             }
439             final IFaceService faceService = mInjector.getFaceService();
440             if (faceService != null) {
441                 faceService.registerAuthenticationStateListener(listener);
442             }
443         }
444 
445         @Override
unregisterAuthenticationStateListener(AuthenticationStateListener listener)446         public void unregisterAuthenticationStateListener(AuthenticationStateListener listener)
447                 throws RemoteException {
448             checkInternalPermission();
449             final IFingerprintService fingerprintService = mInjector.getFingerprintService();
450             if (fingerprintService != null) {
451                 fingerprintService.unregisterAuthenticationStateListener(listener);
452             }
453             final IFaceService faceService = mInjector.getFaceService();
454             if (faceService != null) {
455                 faceService.unregisterAuthenticationStateListener(listener);
456             }
457         }
458 
459         @Override
invalidateAuthenticatorIds(int userId, int fromSensorId, IInvalidationCallback callback)460         public void invalidateAuthenticatorIds(int userId, int fromSensorId,
461                 IInvalidationCallback callback) throws RemoteException {
462             checkInternalPermission();
463 
464             final long identity = Binder.clearCallingIdentity();
465             try {
466                 mBiometricService.invalidateAuthenticatorIds(userId, fromSensorId, callback);
467             } finally {
468                 Binder.restoreCallingIdentity(identity);
469             }
470         }
471 
472         @Override
getAuthenticatorIds(int userId)473         public long[] getAuthenticatorIds(int userId) throws RemoteException {
474             // In this method, we're not checking whether the caller is permitted to use face
475             // API because current authenticator ID is leaked (in a more contrived way) via Android
476             // Keystore (android.security.keystore package): the user of that API can create a key
477             // which requires face authentication for its use, and then query the key's
478             // characteristics (hidden API) which returns, among other things, face
479             // authenticator ID which was active at key creation time.
480             //
481             // Reason: The part of Android Keystore which runs inside an app's process invokes this
482             // method in certain cases. Those cases are not always where the developer demonstrates
483             // explicit intent to use biometric functionality. Thus, to avoiding throwing an
484             // unexpected SecurityException this method does not check whether its caller is
485             // permitted to use face API.
486             //
487             // The permission check should be restored once Android Keystore no longer invokes this
488             // method from inside app processes.
489 
490             final int callingUserId = UserHandle.getCallingUserId();
491             if (userId != callingUserId) {
492                 getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL,
493                         "Must have " + USE_BIOMETRIC_INTERNAL + " permission.");
494             }
495             final long identity = Binder.clearCallingIdentity();
496             try {
497                 return mBiometricService.getAuthenticatorIds(userId);
498             } finally {
499                 Binder.restoreCallingIdentity(identity);
500             }
501         }
502 
503         @Override
resetLockoutTimeBound(IBinder token, String opPackageName, int fromSensorId, int userId, byte[] hardwareAuthToken)504         public void resetLockoutTimeBound(IBinder token, String opPackageName, int fromSensorId,
505                 int userId, byte[] hardwareAuthToken) throws RemoteException {
506             checkInternalPermission();
507 
508             final long identity = Binder.clearCallingIdentity();
509             try {
510                 mBiometricService.resetLockoutTimeBound(token, opPackageName, fromSensorId, userId,
511                         hardwareAuthToken);
512             } finally {
513                 Binder.restoreCallingIdentity(identity);
514             }
515         }
516 
517         @Override
resetLockout(int userId, byte[] hardwareAuthToken)518         public void resetLockout(int userId, byte[] hardwareAuthToken) throws RemoteException {
519             checkInternalPermission();
520             final long identity = Binder.clearCallingIdentity();
521             try {
522                 mBiometricService.resetLockout(userId, hardwareAuthToken);
523             } finally {
524                 Binder.restoreCallingIdentity(identity);
525             }
526         }
527 
528         @Override
getButtonLabel( int userId, String opPackageName, @Authenticators.Types int authenticators)529         public CharSequence getButtonLabel(
530                 int userId,
531                 String opPackageName,
532                 @Authenticators.Types int authenticators) throws RemoteException {
533 
534             // Only allow internal clients to call getButtonLabel with a different userId.
535             final int callingUserId = UserHandle.getCallingUserId();
536 
537             if (userId != callingUserId) {
538                 checkInternalPermission();
539             } else {
540                 checkPermission();
541             }
542 
543             final long identity = Binder.clearCallingIdentity();
544             try {
545                 @BiometricAuthenticator.Modality final int modality =
546                         mBiometricService.getCurrentModality(
547                                 opPackageName, userId, callingUserId, authenticators);
548 
549                 final String result;
550                 switch (getCredentialBackupModality(modality)) {
551                     case BiometricAuthenticator.TYPE_NONE:
552                         result = null;
553                         break;
554                     case BiometricAuthenticator.TYPE_CREDENTIAL:
555                         result = getContext().getString(R.string.screen_lock_app_setting_name);
556                         break;
557                     case BiometricAuthenticator.TYPE_FINGERPRINT:
558                         result = getContext().getString(R.string.fingerprint_app_setting_name);
559                         break;
560                     case BiometricAuthenticator.TYPE_FACE:
561                         result = getContext().getString(R.string.face_app_setting_name);
562                         break;
563                     default:
564                         result = getContext().getString(R.string.biometric_app_setting_name);
565                         break;
566                 }
567 
568                 return result;
569             } finally {
570                 Binder.restoreCallingIdentity(identity);
571             }
572         }
573 
574         @Override
getPromptMessage( int userId, String opPackageName, @Authenticators.Types int authenticators)575         public CharSequence getPromptMessage(
576                 int userId,
577                 String opPackageName,
578                 @Authenticators.Types int authenticators) throws RemoteException {
579 
580             // Only allow internal clients to call getButtonLabel with a different userId.
581             final int callingUserId = UserHandle.getCallingUserId();
582 
583             if (userId != callingUserId) {
584                 checkInternalPermission();
585             } else {
586                 checkPermission();
587             }
588 
589             final long identity = Binder.clearCallingIdentity();
590             try {
591                 @BiometricAuthenticator.Modality final int modality =
592                         mBiometricService.getCurrentModality(
593                                 opPackageName, userId, callingUserId, authenticators);
594 
595                 final boolean isCredentialAllowed = Utils.isCredentialRequested(authenticators);
596 
597                 final String result;
598                 switch (getCredentialBackupModality(modality)) {
599                     case BiometricAuthenticator.TYPE_NONE:
600                         result = null;
601                         break;
602 
603                     case BiometricAuthenticator.TYPE_CREDENTIAL:
604                         result = getContext().getString(
605                                 R.string.screen_lock_dialog_default_subtitle);
606                         break;
607 
608                     case BiometricAuthenticator.TYPE_FINGERPRINT:
609                         if (isCredentialAllowed) {
610                             result = getContext().getString(
611                                     R.string.fingerprint_or_screen_lock_dialog_default_subtitle);
612                         } else {
613                             result = getContext().getString(
614                                     R.string.fingerprint_dialog_default_subtitle);
615                         }
616                         break;
617 
618                     case BiometricAuthenticator.TYPE_FACE:
619                         if (isCredentialAllowed) {
620                             result = getContext().getString(
621                                     R.string.face_or_screen_lock_dialog_default_subtitle);
622                         } else {
623                             result = getContext().getString(R.string.face_dialog_default_subtitle);
624                         }
625                         break;
626 
627                     default:
628                         if (isCredentialAllowed) {
629                             result = getContext().getString(
630                                     R.string.biometric_or_screen_lock_dialog_default_subtitle);
631                         } else {
632                             result = getContext().getString(
633                                     R.string.biometric_dialog_default_subtitle);
634                         }
635                         break;
636                 }
637 
638                 return result;
639             } finally {
640                 Binder.restoreCallingIdentity(identity);
641             }
642         }
643 
644         @Override
getSettingName( int userId, String opPackageName, @Authenticators.Types int authenticators)645         public CharSequence getSettingName(
646                 int userId,
647                 String opPackageName,
648                 @Authenticators.Types int authenticators) throws RemoteException {
649 
650             // Only allow internal clients to call getButtonLabel with a different userId.
651             final int callingUserId = UserHandle.getCallingUserId();
652 
653             if (userId != callingUserId) {
654                 checkInternalPermission();
655             } else {
656                 checkPermission();
657             }
658 
659             final long identity = Binder.clearCallingIdentity();
660             try {
661                 @BiometricAuthenticator.Modality final int modality =
662                         mBiometricService.getSupportedModalities(authenticators);
663 
664                 final String result;
665                 switch (modality) {
666                     // Handle the case of a single supported modality.
667                     case BiometricAuthenticator.TYPE_NONE:
668                         result = null;
669                         break;
670                     case BiometricAuthenticator.TYPE_CREDENTIAL:
671                         result = getContext().getString(R.string.screen_lock_app_setting_name);
672                         break;
673                     case BiometricAuthenticator.TYPE_IRIS:
674                         result = getContext().getString(R.string.biometric_app_setting_name);
675                         break;
676                     case BiometricAuthenticator.TYPE_FINGERPRINT:
677                         result = getContext().getString(R.string.fingerprint_app_setting_name);
678                         break;
679                     case BiometricAuthenticator.TYPE_FACE:
680                         result = getContext().getString(R.string.face_app_setting_name);
681                         break;
682 
683                     // Handle other possible modality combinations.
684                     default:
685                         if ((modality & BiometricAuthenticator.TYPE_CREDENTIAL) == 0) {
686                             // 2+ biometric modalities are supported (but not device credential).
687                             result = getContext().getString(R.string.biometric_app_setting_name);
688                         } else {
689                             @BiometricAuthenticator.Modality final int biometricModality =
690                                     modality & ~BiometricAuthenticator.TYPE_CREDENTIAL;
691                             if (biometricModality == BiometricAuthenticator.TYPE_FINGERPRINT) {
692                                 // Only device credential and fingerprint are supported.
693                                 result = getContext().getString(
694                                         R.string.fingerprint_or_screen_lock_app_setting_name);
695                             } else if (biometricModality == BiometricAuthenticator.TYPE_FACE) {
696                                 // Only device credential and face are supported.
697                                 result = getContext().getString(
698                                         R.string.face_or_screen_lock_app_setting_name);
699                             } else {
700                                 // Device credential and 1+ other biometric(s) are supported.
701                                 result = getContext().getString(
702                                         R.string.biometric_or_screen_lock_app_setting_name);
703                             }
704                         }
705                         break;
706                 }
707                 return result;
708             } finally {
709                 Binder.restoreCallingIdentity(identity);
710             }
711         }
712     }
713 
AuthService(Context context)714     public AuthService(Context context) {
715         this(context, new Injector());
716     }
717 
AuthService(Context context, Injector injector)718     public AuthService(Context context, Injector injector) {
719         super(context);
720 
721         mInjector = injector;
722         mImpl = new AuthServiceImpl();
723     }
724 
725 
726     /**
727      * Registration of all HIDL and AIDL biometric HALs starts here.
728      * The flow looks like this:
729      * AuthService
730      * └── .onStart()
731      *     └── .registerAuthenticators(...)
732      *         ├── FaceService.registerAuthenticators(...)
733      *         │   └── for (p : serviceProviders)
734      *         │       └── for (s : p.sensors)
735      *         │           └── BiometricService.registerAuthenticator(s)
736      *         │
737      *         ├── FingerprintService.registerAuthenticators(...)
738      *         │   └── for (p : serviceProviders)
739      *         │       └── for (s : p.sensors)
740      *         │           └── BiometricService.registerAuthenticator(s)
741      *         │
742      *         └── IrisService.registerAuthenticators(...)
743      *             └── for (p : serviceProviders)
744      *                 └── for (s : p.sensors)
745      *                     └── BiometricService.registerAuthenticator(s)
746      */
747     @Override
onStart()748     public void onStart() {
749         mBiometricService = mInjector.getBiometricService();
750 
751         final SensorConfig[] hidlConfigs;
752         if (!mInjector.isHidlDisabled(getContext())) {
753             final int firstApiLevel = SystemProperties.getInt(SYSPROP_FIRST_API_LEVEL, 0);
754             final int apiLevel = SystemProperties.getInt(SYSPROP_API_LEVEL, firstApiLevel);
755             String[] configStrings = mInjector.getConfiguration(getContext());
756             if (configStrings.length == 0 && apiLevel == Build.VERSION_CODES.R) {
757                 // For backwards compatibility with R where biometrics could work without being
758                 // configured in config_biometric_sensors. In the absence of a vendor provided
759                 // configuration, we assume the weakest biometric strength (i.e. convenience).
760                 Slog.w(TAG, "Found R vendor partition without config_biometric_sensors");
761                 configStrings = generateRSdkCompatibleConfiguration();
762             }
763             hidlConfigs = new SensorConfig[configStrings.length];
764             for (int i = 0; i < configStrings.length; ++i) {
765                 hidlConfigs[i] = new SensorConfig(configStrings[i]);
766             }
767         } else {
768             hidlConfigs = null;
769         }
770 
771         registerAuthenticators();
772         mInjector.publishBinderService(this, mImpl);
773     }
774 
registerAuthenticators()775     private void registerAuthenticators() {
776         BiometricHandlerProvider handlerProvider = mInjector.getBiometricHandlerProvider();
777 
778         registerFingerprintSensors(mInjector.getFingerprintAidlInstances(),
779                 mInjector.getFingerprintConfiguration(getContext()), getContext(),
780                 mInjector.getFingerprintService(), handlerProvider);
781         registerFaceSensors(mInjector.getFaceAidlInstances(),
782                 mInjector.getFaceConfiguration(getContext()), getContext(),
783                 mInjector.getFaceService(), handlerProvider);
784         registerIrisSensors(mInjector.getIrisConfiguration(getContext()));
785     }
786 
registerIrisSensors(String[] hidlConfigStrings)787     private void registerIrisSensors(String[] hidlConfigStrings) {
788         final SensorConfig[] hidlConfigs;
789         if (!mInjector.isHidlDisabled(getContext())) {
790             final int firstApiLevel = SystemProperties.getInt(SYSPROP_FIRST_API_LEVEL, 0);
791             final int apiLevel = SystemProperties.getInt(SYSPROP_API_LEVEL, firstApiLevel);
792             if (hidlConfigStrings.length == 0 && apiLevel == Build.VERSION_CODES.R) {
793                 // For backwards compatibility with R where biometrics could work without being
794                 // configured in config_biometric_sensors. In the absence of a vendor provided
795                 // configuration, we assume the weakest biometric strength (i.e. convenience).
796                 Slog.w(TAG, "Found R vendor partition without config_biometric_sensors");
797                 hidlConfigStrings = generateRSdkCompatibleConfiguration();
798             }
799             hidlConfigs = new SensorConfig[hidlConfigStrings.length];
800             for (int i = 0; i < hidlConfigStrings.length; ++i) {
801                 hidlConfigs[i] = new SensorConfig(hidlConfigStrings[i]);
802             }
803         } else {
804             hidlConfigs = null;
805         }
806 
807         final List<SensorPropertiesInternal> hidlIrisSensors = new ArrayList<>();
808 
809         if (hidlConfigs != null) {
810             for (SensorConfig sensor : hidlConfigs) {
811                 switch (sensor.modality) {
812                     case TYPE_IRIS:
813                         hidlIrisSensors.add(getHidlIrisSensorProps(sensor.id, sensor.strength));
814                         break;
815 
816                     default:
817                         Slog.e(TAG, "Unknown modality: " + sensor.modality);
818                 }
819             }
820         }
821 
822         final IIrisService irisService = mInjector.getIrisService();
823         if (irisService != null) {
824             try {
825                 irisService.registerAuthenticators(hidlIrisSensors);
826             } catch (RemoteException e) {
827                 Slog.e(TAG, "RemoteException when registering iris authenticators", e);
828             }
829         } else if (hidlIrisSensors.size() > 0) {
830             Slog.e(TAG, "HIDL iris configuration exists, but IrisService is null.");
831         }
832     }
833 
834     /**
835      * This method is invoked on {@link BiometricHandlerProvider.mFaceHandler}.
836      */
registerFaceSensors(final String[] faceAidlInstances, final String[] hidlConfigStrings, final Context context, final IFaceService faceService, final BiometricHandlerProvider handlerProvider)837     private static void registerFaceSensors(final String[] faceAidlInstances,
838             final String[] hidlConfigStrings, final Context context,
839             final IFaceService faceService, final BiometricHandlerProvider handlerProvider) {
840         if ((hidlConfigStrings == null || hidlConfigStrings.length == 0)
841                 && (faceAidlInstances == null || faceAidlInstances.length == 0)) {
842             Slog.d(TAG, "No face sensors.");
843             return;
844         }
845 
846         boolean tempResetLockoutRequiresChallenge = false;
847 
848         if (hidlConfigStrings != null && hidlConfigStrings.length > 0) {
849             for (String configString : hidlConfigStrings) {
850                 try {
851                     SensorConfig sensor = new SensorConfig(configString);
852                     switch (sensor.modality) {
853                         case BiometricAuthenticator.TYPE_FACE:
854                             tempResetLockoutRequiresChallenge = true;
855                             break;
856                     }
857                 } catch (Exception e) {
858                     Slog.e(TAG, "Error parsing configString: " + configString, e);
859                 }
860             }
861         }
862 
863         final boolean resetLockoutRequiresChallenge = tempResetLockoutRequiresChallenge;
864 
865         handlerProvider.getFaceHandler().post(() -> {
866             final FaceSensorConfigurations mFaceSensorConfigurations =
867                     new FaceSensorConfigurations(resetLockoutRequiresChallenge);
868 
869             if (hidlConfigStrings != null && hidlConfigStrings.length > 0) {
870                 mFaceSensorConfigurations.addHidlConfigs(hidlConfigStrings, context);
871             }
872 
873             if (faceAidlInstances != null && faceAidlInstances.length > 0) {
874                 mFaceSensorConfigurations.addAidlConfigs(faceAidlInstances);
875             }
876 
877             if (faceService != null) {
878                 try {
879                     faceService.registerAuthenticators(mFaceSensorConfigurations);
880                 } catch (RemoteException e) {
881                     Slog.e(TAG, "RemoteException when registering face authenticators", e);
882                 }
883             } else if (mFaceSensorConfigurations.hasSensorConfigurations()) {
884                 Slog.e(TAG, "Face configuration exists, but FaceService is null.");
885             }
886         });
887     }
888 
889     /**
890      * This method is invoked on {@link BiometricHandlerProvider.mFingerprintHandler}.
891      */
registerFingerprintSensors(final String[] fingerprintAidlInstances, final String[] hidlConfigStrings, final Context context, final IFingerprintService fingerprintService, final BiometricHandlerProvider handlerProvider)892     private static void registerFingerprintSensors(final String[] fingerprintAidlInstances,
893             final String[] hidlConfigStrings, final Context context,
894             final IFingerprintService fingerprintService,
895             final BiometricHandlerProvider handlerProvider) {
896         if ((hidlConfigStrings == null || hidlConfigStrings.length == 0)
897                 && (fingerprintAidlInstances == null || fingerprintAidlInstances.length == 0)) {
898             Slog.d(TAG, "No fingerprint sensors.");
899             return;
900         }
901 
902         handlerProvider.getFingerprintHandler().post(() -> {
903             final FingerprintSensorConfigurations mFingerprintSensorConfigurations =
904                     new FingerprintSensorConfigurations(!(hidlConfigStrings != null
905                             && hidlConfigStrings.length > 0));
906 
907             if (hidlConfigStrings != null && hidlConfigStrings.length > 0) {
908                 mFingerprintSensorConfigurations.addHidlSensors(hidlConfigStrings, context);
909             }
910 
911             if (fingerprintAidlInstances != null && fingerprintAidlInstances.length > 0) {
912                 mFingerprintSensorConfigurations.addAidlSensors(fingerprintAidlInstances);
913             }
914 
915             if (fingerprintService != null) {
916                 try {
917                     fingerprintService.registerAuthenticators(mFingerprintSensorConfigurations);
918                 } catch (RemoteException e) {
919                     Slog.e(TAG, "RemoteException when registering fingerprint authenticators", e);
920                 }
921             } else if (mFingerprintSensorConfigurations.hasSensorConfigurations()) {
922                 Slog.e(TAG, "Fingerprint configuration exists, but FingerprintService is null.");
923             }
924         });
925     }
926 
927     /**
928      * Generates an array of string configs with entries that correspond to the biometric features
929      * declared on the device. Returns an empty array if no biometric features are declared.
930      * Biometrics are assumed to be of the weakest strength class, i.e. convenience.
931      */
generateRSdkCompatibleConfiguration()932     private @NonNull String[] generateRSdkCompatibleConfiguration() {
933         final PackageManager pm = getContext().getPackageManager();
934         final ArrayList<String> modalities = new ArrayList<>();
935         if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
936             modalities.add(String.valueOf(BiometricAuthenticator.TYPE_FINGERPRINT));
937         }
938         if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
939             modalities.add(String.valueOf(BiometricAuthenticator.TYPE_FACE));
940         }
941         final String strength = String.valueOf(Authenticators.BIOMETRIC_CONVENIENCE);
942         final String[] configStrings = new String[modalities.size()];
943         for (int i = 0; i < modalities.size(); ++i) {
944             final String id = String.valueOf(i);
945             final String modality = modalities.get(i);
946             configStrings[i] = String.join(":" /* delimiter */, id, modality, strength);
947         }
948         Slog.d(TAG, "Generated config_biometric_sensors: " + Arrays.toString(configStrings));
949         return configStrings;
950     }
951 
checkInternalPermission()952     private void checkInternalPermission() {
953         getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL,
954                 "Must have USE_BIOMETRIC_INTERNAL permission");
955     }
956 
checkBiometricAdvancedPermission()957     private void checkBiometricAdvancedPermission() {
958         getContext().enforceCallingOrSelfPermission(SET_BIOMETRIC_DIALOG_ADVANCED,
959                 "Must have SET_BIOMETRIC_DIALOG_ADVANCED permission");
960     }
961 
checkPermission()962     private void checkPermission() {
963         if (getContext().checkCallingOrSelfPermission(USE_FINGERPRINT)
964                 != PackageManager.PERMISSION_GRANTED) {
965             getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC,
966                     "Must have USE_BIOMETRIC permission");
967         }
968     }
969 
checkAppOps(int uid, String opPackageName, String reason)970     private boolean checkAppOps(int uid, String opPackageName, String reason) {
971         return mInjector.getAppOps(getContext()).noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid,
972                 opPackageName, null /* attributionTag */, reason) == AppOpsManager.MODE_ALLOWED;
973     }
974 
975     @BiometricAuthenticator.Modality
getCredentialBackupModality(@iometricAuthenticator.Modality int modality)976     private static int getCredentialBackupModality(@BiometricAuthenticator.Modality int modality) {
977         return modality == BiometricAuthenticator.TYPE_CREDENTIAL
978                 ? modality : (modality & ~BiometricAuthenticator.TYPE_CREDENTIAL);
979     }
980 
981 
getHidlFingerprintSensorProps(int sensorId, @BiometricManager.Authenticators.Types int strength)982     private FingerprintSensorPropertiesInternal getHidlFingerprintSensorProps(int sensorId,
983             @BiometricManager.Authenticators.Types int strength) {
984         // The existence of config_udfps_sensor_props indicates that the sensor is UDFPS.
985         final int[] udfpsProps = getContext().getResources().getIntArray(
986                 com.android.internal.R.array.config_udfps_sensor_props);
987 
988         final boolean isUdfps = !ArrayUtils.isEmpty(udfpsProps);
989 
990         // config_is_powerbutton_fps indicates whether device has a power button fingerprint sensor.
991         final boolean isPowerbuttonFps = getContext().getResources().getBoolean(
992                 R.bool.config_is_powerbutton_fps);
993 
994         final @FingerprintSensorProperties.SensorType int sensorType;
995         if (isUdfps) {
996             sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
997         } else if (isPowerbuttonFps) {
998             sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON;
999         } else {
1000             sensorType = FingerprintSensorProperties.TYPE_REAR;
1001         }
1002 
1003         // IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT
1004         // cannot be checked.
1005         final boolean resetLockoutRequiresHardwareAuthToken = false;
1006         final int maxEnrollmentsPerUser = getContext().getResources().getInteger(
1007                 R.integer.config_fingerprintMaxTemplatesPerUser);
1008 
1009         final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
1010         if (isUdfps && udfpsProps.length == 3) {
1011             return new FingerprintSensorPropertiesInternal(sensorId,
1012                     Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
1013                     componentInfo, sensorType, true /* halControlsIllumination */,
1014                     resetLockoutRequiresHardwareAuthToken,
1015                     List.of(new SensorLocationInternal("" /* display */, udfpsProps[0],
1016                             udfpsProps[1], udfpsProps[2])));
1017         } else {
1018             return new FingerprintSensorPropertiesInternal(sensorId,
1019                     Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
1020                     componentInfo, sensorType, resetLockoutRequiresHardwareAuthToken);
1021         }
1022     }
1023 
getHidlFaceSensorProps(int sensorId, @BiometricManager.Authenticators.Types int strength)1024     private FaceSensorPropertiesInternal getHidlFaceSensorProps(int sensorId,
1025             @BiometricManager.Authenticators.Types int strength) {
1026         final boolean supportsSelfIllumination = getContext().getResources().getBoolean(
1027                 R.bool.config_faceAuthSupportsSelfIllumination);
1028         final int maxTemplatesAllowed = getContext().getResources().getInteger(
1029                 R.integer.config_faceMaxTemplatesPerUser);
1030         final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
1031         final boolean supportsFaceDetect = false;
1032         final boolean resetLockoutRequiresChallenge = true;
1033         return new FaceSensorPropertiesInternal(sensorId,
1034                 Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed,
1035                 componentInfo, FaceSensorProperties.TYPE_UNKNOWN, supportsFaceDetect,
1036                 supportsSelfIllumination, resetLockoutRequiresChallenge);
1037     }
1038 
getHidlIrisSensorProps(int sensorId, @BiometricManager.Authenticators.Types int strength)1039     private SensorPropertiesInternal getHidlIrisSensorProps(int sensorId,
1040             @BiometricManager.Authenticators.Types int strength) {
1041         final int maxEnrollmentsPerUser = 1;
1042         final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
1043         final boolean resetLockoutRequiresHardwareAuthToken = false;
1044         final boolean resetLockoutRequiresChallenge = false;
1045         return new SensorPropertiesInternal(sensorId,
1046                 Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
1047                 componentInfo, resetLockoutRequiresHardwareAuthToken,
1048                 resetLockoutRequiresChallenge);
1049     }
1050 }
1051