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