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