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