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