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