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