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