1 /* 2 * Copyright (C) 2020 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.sensors.fingerprint.hidl; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.ActivityManager; 22 import android.app.ActivityTaskManager; 23 import android.app.SynchronousUserSwitchObserver; 24 import android.app.TaskStackListener; 25 import android.app.UserSwitchObserver; 26 import android.content.Context; 27 import android.content.pm.UserInfo; 28 import android.hardware.biometrics.BiometricConstants; 29 import android.hardware.biometrics.BiometricsProtoEnums; 30 import android.hardware.biometrics.IInvalidationCallback; 31 import android.hardware.biometrics.ITestSession; 32 import android.hardware.biometrics.ITestSessionCallback; 33 import android.hardware.biometrics.fingerprint.PointerContext; 34 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; 35 import android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprintClientCallback; 36 import android.hardware.fingerprint.Fingerprint; 37 import android.hardware.fingerprint.FingerprintAuthenticateOptions; 38 import android.hardware.fingerprint.FingerprintManager; 39 import android.hardware.fingerprint.FingerprintSensorProperties; 40 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 41 import android.hardware.fingerprint.IFingerprintServiceReceiver; 42 import android.hardware.fingerprint.ISidefpsController; 43 import android.hardware.fingerprint.IUdfpsOverlayController; 44 import android.os.Handler; 45 import android.os.IBinder; 46 import android.os.IHwBinder; 47 import android.os.RemoteException; 48 import android.os.UserHandle; 49 import android.os.UserManager; 50 import android.util.Slog; 51 import android.util.proto.ProtoOutputStream; 52 53 import com.android.internal.annotations.VisibleForTesting; 54 import com.android.internal.util.FrameworkStatsLog; 55 import com.android.server.biometrics.AuthenticationStatsCollector; 56 import com.android.server.biometrics.SensorServiceStateProto; 57 import com.android.server.biometrics.SensorStateProto; 58 import com.android.server.biometrics.UserStateProto; 59 import com.android.server.biometrics.Utils; 60 import com.android.server.biometrics.fingerprint.FingerprintServiceDumpProto; 61 import com.android.server.biometrics.fingerprint.FingerprintUserStatsProto; 62 import com.android.server.biometrics.fingerprint.PerformanceStatsProto; 63 import com.android.server.biometrics.log.BiometricContext; 64 import com.android.server.biometrics.log.BiometricLogger; 65 import com.android.server.biometrics.sensors.AcquisitionClient; 66 import com.android.server.biometrics.sensors.AuthenticationClient; 67 import com.android.server.biometrics.sensors.AuthenticationConsumer; 68 import com.android.server.biometrics.sensors.BaseClientMonitor; 69 import com.android.server.biometrics.sensors.BiometricNotificationImpl; 70 import com.android.server.biometrics.sensors.BiometricScheduler; 71 import com.android.server.biometrics.sensors.BiometricStateCallback; 72 import com.android.server.biometrics.sensors.ClientMonitorCallback; 73 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; 74 import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback; 75 import com.android.server.biometrics.sensors.EnumerateConsumer; 76 import com.android.server.biometrics.sensors.ErrorConsumer; 77 import com.android.server.biometrics.sensors.LockoutResetDispatcher; 78 import com.android.server.biometrics.sensors.LockoutTracker; 79 import com.android.server.biometrics.sensors.PerformanceTracker; 80 import com.android.server.biometrics.sensors.RemovalConsumer; 81 import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; 82 import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; 83 import com.android.server.biometrics.sensors.fingerprint.ServiceProvider; 84 import com.android.server.biometrics.sensors.fingerprint.Udfps; 85 86 import org.json.JSONArray; 87 import org.json.JSONException; 88 import org.json.JSONObject; 89 90 import java.io.FileDescriptor; 91 import java.io.PrintWriter; 92 import java.util.ArrayList; 93 import java.util.Collections; 94 import java.util.HashMap; 95 import java.util.List; 96 import java.util.Map; 97 import java.util.concurrent.atomic.AtomicLong; 98 import java.util.function.Supplier; 99 100 /** 101 * Supports a single instance of the {@link android.hardware.biometrics.fingerprint.V2_1} or 102 * its extended minor versions. 103 */ 104 public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider { 105 106 private static final String TAG = "Fingerprint21"; 107 private static final int ENROLL_TIMEOUT_SEC = 60; 108 109 private boolean mTestHalEnabled; 110 111 final Context mContext; 112 @NonNull private final BiometricStateCallback mBiometricStateCallback; 113 private final ActivityTaskManager mActivityTaskManager; 114 @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties; 115 private final BiometricScheduler mScheduler; 116 private final Handler mHandler; 117 private final LockoutResetDispatcher mLockoutResetDispatcher; 118 private final LockoutFrameworkImpl mLockoutTracker; 119 private final BiometricTaskStackListener mTaskStackListener; 120 private final Supplier<IBiometricsFingerprint> mLazyDaemon; 121 private final Map<Integer, Long> mAuthenticatorIds; 122 123 @Nullable private IBiometricsFingerprint mDaemon; 124 @NonNull private final HalResultController mHalResultController; 125 @Nullable private IUdfpsOverlayController mUdfpsOverlayController; 126 @Nullable private ISidefpsController mSidefpsController; 127 @NonNull private final BiometricContext mBiometricContext; 128 @NonNull private final AuthenticationStatsCollector mAuthenticationStatsCollector; 129 // for requests that do not use biometric prompt 130 @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); 131 private int mCurrentUserId = UserHandle.USER_NULL; 132 private final boolean mIsUdfps; 133 private final int mSensorId; 134 private final boolean mIsPowerbuttonFps; 135 136 private final class BiometricTaskStackListener extends TaskStackListener { 137 @Override onTaskStackChanged()138 public void onTaskStackChanged() { 139 mHandler.post(() -> { 140 final BaseClientMonitor client = mScheduler.getCurrentClient(); 141 if (!(client instanceof AuthenticationClient)) { 142 Slog.e(TAG, "Task stack changed for client: " + client); 143 return; 144 } 145 if (Utils.isKeyguard(mContext, client.getOwnerString()) 146 || Utils.isSystem(mContext, client.getOwnerString())) { 147 return; // Keyguard is always allowed 148 } 149 150 if (Utils.isBackground(client.getOwnerString()) 151 && !client.isAlreadyDone()) { 152 Slog.e(TAG, "Stopping background authentication," 153 + " currentClient: " + client); 154 mScheduler.cancelAuthenticationOrDetection( 155 client.getToken(), client.getRequestId()); 156 } 157 }); 158 } 159 } 160 161 private final LockoutFrameworkImpl.LockoutResetCallback mLockoutResetCallback = 162 new LockoutFrameworkImpl.LockoutResetCallback() { 163 @Override 164 public void onLockoutReset(int userId) { 165 mLockoutResetDispatcher.notifyLockoutResetCallbacks(mSensorProperties.sensorId); 166 } 167 }; 168 169 private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() { 170 @Override 171 public void onUserSwitching(int newUserId) { 172 scheduleInternalCleanup(newUserId, null /* callback */); 173 } 174 }; 175 176 public static class HalResultController extends IBiometricsFingerprintClientCallback.Stub { 177 178 /** 179 * Interface to sends results to the HalResultController's owner. 180 */ 181 public interface Callback { 182 /** 183 * Invoked when the HAL sends ERROR_HW_UNAVAILABLE. 184 */ onHardwareUnavailable()185 void onHardwareUnavailable(); 186 } 187 188 private final int mSensorId; 189 @NonNull private final Context mContext; 190 @NonNull final Handler mHandler; 191 @NonNull final BiometricScheduler mScheduler; 192 @Nullable private Callback mCallback; 193 HalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler, @NonNull BiometricScheduler scheduler)194 HalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler, 195 @NonNull BiometricScheduler scheduler) { 196 mSensorId = sensorId; 197 mContext = context; 198 mHandler = handler; 199 mScheduler = scheduler; 200 } 201 setCallback(@ullable Callback callback)202 public void setCallback(@Nullable Callback callback) { 203 mCallback = callback; 204 } 205 206 @Override onEnrollResult(long deviceId, int fingerId, int groupId, int remaining)207 public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { 208 mHandler.post(() -> { 209 final BaseClientMonitor client = mScheduler.getCurrentClient(); 210 if (!(client instanceof FingerprintEnrollClient)) { 211 Slog.e(TAG, "onEnrollResult for non-enroll client: " 212 + Utils.getClientName(client)); 213 return; 214 } 215 216 final int currentUserId = client.getTargetUserId(); 217 final CharSequence name = FingerprintUtils.getLegacyInstance(mSensorId) 218 .getUniqueName(mContext, currentUserId); 219 final Fingerprint fingerprint = new Fingerprint(name, groupId, fingerId, deviceId); 220 221 final FingerprintEnrollClient enrollClient = (FingerprintEnrollClient) client; 222 enrollClient.onEnrollResult(fingerprint, remaining); 223 }); 224 } 225 226 @Override onAcquired(long deviceId, int acquiredInfo, int vendorCode)227 public void onAcquired(long deviceId, int acquiredInfo, int vendorCode) { 228 onAcquired_2_2(deviceId, acquiredInfo, vendorCode); 229 } 230 231 @Override onAcquired_2_2(long deviceId, int acquiredInfo, int vendorCode)232 public void onAcquired_2_2(long deviceId, int acquiredInfo, int vendorCode) { 233 mHandler.post(() -> { 234 final BaseClientMonitor client = mScheduler.getCurrentClient(); 235 if (!(client instanceof AcquisitionClient)) { 236 Slog.e(TAG, "onAcquired for non-acquisition client: " 237 + Utils.getClientName(client)); 238 return; 239 } 240 241 final AcquisitionClient<?> acquisitionClient = (AcquisitionClient<?>) client; 242 acquisitionClient.onAcquired(acquiredInfo, vendorCode); 243 }); 244 } 245 246 @Override onAuthenticated(long deviceId, int fingerId, int groupId, ArrayList<Byte> token)247 public void onAuthenticated(long deviceId, int fingerId, int groupId, 248 ArrayList<Byte> token) { 249 mHandler.post(() -> { 250 final BaseClientMonitor client = mScheduler.getCurrentClient(); 251 if (!(client instanceof AuthenticationConsumer)) { 252 Slog.e(TAG, "onAuthenticated for non-authentication consumer: " 253 + Utils.getClientName(client)); 254 return; 255 } 256 257 final AuthenticationConsumer authenticationConsumer = 258 (AuthenticationConsumer) client; 259 final boolean authenticated = fingerId != 0; 260 final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId); 261 authenticationConsumer.onAuthenticated(fp, authenticated, token); 262 }); 263 } 264 265 @Override onError(long deviceId, int error, int vendorCode)266 public void onError(long deviceId, int error, int vendorCode) { 267 mHandler.post(() -> { 268 final BaseClientMonitor client = mScheduler.getCurrentClient(); 269 Slog.d(TAG, "handleError" 270 + ", client: " + Utils.getClientName(client) 271 + ", error: " + error 272 + ", vendorCode: " + vendorCode); 273 if (!(client instanceof ErrorConsumer)) { 274 Slog.e(TAG, "onError for non-error consumer: " + Utils.getClientName(client)); 275 return; 276 } 277 278 final ErrorConsumer errorConsumer = (ErrorConsumer) client; 279 errorConsumer.onError(error, vendorCode); 280 281 if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) { 282 Slog.e(TAG, "Got ERROR_HW_UNAVAILABLE"); 283 if (mCallback != null) { 284 mCallback.onHardwareUnavailable(); 285 } 286 } 287 }); 288 } 289 290 @Override onRemoved(long deviceId, int fingerId, int groupId, int remaining)291 public void onRemoved(long deviceId, int fingerId, int groupId, int remaining) { 292 mHandler.post(() -> { 293 Slog.d(TAG, "Removed, fingerId: " + fingerId + ", remaining: " + remaining); 294 final BaseClientMonitor client = mScheduler.getCurrentClient(); 295 if (!(client instanceof RemovalConsumer)) { 296 Slog.e(TAG, "onRemoved for non-removal consumer: " 297 + Utils.getClientName(client)); 298 return; 299 } 300 301 final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId); 302 final RemovalConsumer removalConsumer = (RemovalConsumer) client; 303 removalConsumer.onRemoved(fp, remaining); 304 }); 305 } 306 307 @Override onEnumerate(long deviceId, int fingerId, int groupId, int remaining)308 public void onEnumerate(long deviceId, int fingerId, int groupId, int remaining) { 309 mHandler.post(() -> { 310 final BaseClientMonitor client = mScheduler.getCurrentClient(); 311 if (!(client instanceof EnumerateConsumer)) { 312 Slog.e(TAG, "onEnumerate for non-enumerate consumer: " 313 + Utils.getClientName(client)); 314 return; 315 } 316 317 final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId); 318 final EnumerateConsumer enumerateConsumer = (EnumerateConsumer) client; 319 enumerateConsumer.onEnumerationResult(fp, remaining); 320 }); 321 } 322 } 323 324 @VisibleForTesting Fingerprint21(@onNull Context context, @NonNull BiometricStateCallback biometricStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull BiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull HalResultController controller, @NonNull BiometricContext biometricContext)325 Fingerprint21(@NonNull Context context, 326 @NonNull BiometricStateCallback biometricStateCallback, 327 @NonNull FingerprintSensorPropertiesInternal sensorProps, 328 @NonNull BiometricScheduler scheduler, 329 @NonNull Handler handler, 330 @NonNull LockoutResetDispatcher lockoutResetDispatcher, 331 @NonNull HalResultController controller, 332 @NonNull BiometricContext biometricContext) { 333 mContext = context; 334 mBiometricStateCallback = biometricStateCallback; 335 mBiometricContext = biometricContext; 336 337 mSensorProperties = sensorProps; 338 mSensorId = sensorProps.sensorId; 339 mIsUdfps = sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL 340 || sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC; 341 mIsPowerbuttonFps = sensorProps.sensorType == FingerprintSensorProperties.TYPE_POWER_BUTTON; 342 343 mScheduler = scheduler; 344 mHandler = handler; 345 mActivityTaskManager = ActivityTaskManager.getInstance(); 346 mTaskStackListener = new BiometricTaskStackListener(); 347 mAuthenticatorIds = Collections.synchronizedMap(new HashMap<>()); 348 mLazyDaemon = Fingerprint21.this::getDaemon; 349 mLockoutResetDispatcher = lockoutResetDispatcher; 350 mLockoutTracker = new LockoutFrameworkImpl(context, mLockoutResetCallback); 351 mHalResultController = controller; 352 mHalResultController.setCallback(() -> { 353 mDaemon = null; 354 mCurrentUserId = UserHandle.USER_NULL; 355 }); 356 357 mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext, 358 BiometricsProtoEnums.MODALITY_FINGERPRINT, new BiometricNotificationImpl()); 359 360 try { 361 ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG); 362 } catch (RemoteException e) { 363 Slog.e(TAG, "Unable to register user switch observer"); 364 } 365 } 366 newInstance(@onNull Context context, @NonNull BiometricStateCallback biometricStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher)367 public static Fingerprint21 newInstance(@NonNull Context context, 368 @NonNull BiometricStateCallback biometricStateCallback, 369 @NonNull FingerprintSensorPropertiesInternal sensorProps, 370 @NonNull Handler handler, 371 @NonNull LockoutResetDispatcher lockoutResetDispatcher, 372 @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { 373 final BiometricScheduler scheduler = 374 new BiometricScheduler(TAG, 375 BiometricScheduler.sensorTypeFromFingerprintProperties(sensorProps), 376 gestureAvailabilityDispatcher); 377 final HalResultController controller = new HalResultController(sensorProps.sensorId, 378 context, handler, scheduler); 379 return new Fingerprint21(context, biometricStateCallback, sensorProps, scheduler, handler, 380 lockoutResetDispatcher, controller, BiometricContext.getInstance(context)); 381 } 382 383 @Override serviceDied(long cookie)384 public void serviceDied(long cookie) { 385 Slog.e(TAG, "HAL died"); 386 mHandler.post(() -> { 387 PerformanceTracker.getInstanceForSensorId(mSensorProperties.sensorId) 388 .incrementHALDeathCount(); 389 mDaemon = null; 390 mCurrentUserId = UserHandle.USER_NULL; 391 392 final BaseClientMonitor client = mScheduler.getCurrentClient(); 393 if (client instanceof ErrorConsumer) { 394 Slog.e(TAG, "Sending ERROR_HW_UNAVAILABLE for client: " + client); 395 final ErrorConsumer errorConsumer = (ErrorConsumer) client; 396 errorConsumer.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 397 0 /* vendorCode */); 398 399 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, 400 BiometricsProtoEnums.MODALITY_FINGERPRINT, 401 BiometricsProtoEnums.ISSUE_HAL_DEATH, 402 -1 /* sensorId */); 403 } 404 405 mScheduler.recordCrashState(); 406 mScheduler.reset(); 407 }); 408 } 409 410 @VisibleForTesting getDaemon()411 synchronized IBiometricsFingerprint getDaemon() { 412 if (mTestHalEnabled) { 413 final TestHal testHal = new TestHal(mContext, mSensorId); 414 testHal.setNotify(mHalResultController); 415 return testHal; 416 } 417 418 if (mDaemon != null) { 419 return mDaemon; 420 } 421 422 Slog.d(TAG, "Daemon was null, reconnecting, current operation: " 423 + mScheduler.getCurrentClient()); 424 try { 425 mDaemon = IBiometricsFingerprint.getService(); 426 } catch (java.util.NoSuchElementException e) { 427 // Service doesn't exist or cannot be opened. 428 Slog.w(TAG, "NoSuchElementException", e); 429 } catch (RemoteException e) { 430 Slog.e(TAG, "Failed to get fingerprint HAL", e); 431 } 432 433 if (mDaemon == null) { 434 Slog.w(TAG, "Fingerprint HAL not available"); 435 return null; 436 } 437 438 mDaemon.asBinder().linkToDeath(this, 0 /* flags */); 439 440 // HAL ID for these HIDL versions are only used to determine if callbacks have been 441 // successfully set. 442 long halId = 0; 443 try { 444 halId = mDaemon.setNotify(mHalResultController); 445 } catch (RemoteException e) { 446 Slog.e(TAG, "Failed to set callback for fingerprint HAL", e); 447 mDaemon = null; 448 } 449 450 Slog.d(TAG, "Fingerprint HAL ready, HAL ID: " + halId); 451 if (halId != 0) { 452 scheduleLoadAuthenticatorIds(); 453 scheduleInternalCleanup(ActivityManager.getCurrentUser(), null /* callback */); 454 } else { 455 Slog.e(TAG, "Unable to set callback"); 456 mDaemon = null; 457 } 458 459 return mDaemon; 460 } 461 getUdfpsOverlayController()462 @Nullable IUdfpsOverlayController getUdfpsOverlayController() { 463 return mUdfpsOverlayController; 464 } 465 scheduleLoadAuthenticatorIds()466 private void scheduleLoadAuthenticatorIds() { 467 // Note that this can be performed on the scheduler (as opposed to being done immediately 468 // when the HAL is (re)loaded, since 469 // 1) If this is truly the first time it's being performed (e.g. system has just started), 470 // this will be run very early and way before any applications need to generate keys. 471 // 2) If this is being performed to refresh the authenticatorIds (e.g. HAL crashed and has 472 // just been reloaded), the framework already has a cache of the authenticatorIds. This 473 // is safe because authenticatorIds only change when A) new template has been enrolled, 474 // or B) all templates are removed. 475 mHandler.post(() -> { 476 for (UserInfo user : UserManager.get(mContext).getAliveUsers()) { 477 final int targetUserId = user.id; 478 if (!mAuthenticatorIds.containsKey(targetUserId)) { 479 scheduleUpdateActiveUserWithoutHandler(targetUserId, true /* force */); 480 } 481 } 482 }); 483 } 484 scheduleUpdateActiveUserWithoutHandler(int targetUserId)485 private void scheduleUpdateActiveUserWithoutHandler(int targetUserId) { 486 scheduleUpdateActiveUserWithoutHandler(targetUserId, false /* force */); 487 } 488 489 /** 490 * Schedules the {@link FingerprintUpdateActiveUserClient} without posting the work onto the 491 * handler. Many/most APIs are user-specific. However, the HAL requires explicit "setActiveUser" 492 * invocation prior to authenticate/enroll/etc. Thus, internally we usually want to schedule 493 * this operation on the same lambda/runnable as those operations so that the ordering is 494 * correct. 495 * 496 * @param targetUserId Switch to this user, and update their authenticatorId 497 * @param force Always retrieve the authenticatorId, even if we are already the targetUserId 498 */ scheduleUpdateActiveUserWithoutHandler(int targetUserId, boolean force)499 private void scheduleUpdateActiveUserWithoutHandler(int targetUserId, boolean force) { 500 final boolean hasEnrolled = 501 !getEnrolledFingerprints(mSensorProperties.sensorId, targetUserId).isEmpty(); 502 final FingerprintUpdateActiveUserClient client = 503 new FingerprintUpdateActiveUserClient(mContext, mLazyDaemon, targetUserId, 504 mContext.getOpPackageName(), mSensorProperties.sensorId, 505 createLogger(BiometricsProtoEnums.ACTION_UNKNOWN, 506 BiometricsProtoEnums.CLIENT_UNKNOWN, 507 mAuthenticationStatsCollector), 508 mBiometricContext, 509 this::getCurrentUser, hasEnrolled, mAuthenticatorIds, force); 510 mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() { 511 @Override 512 public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, 513 boolean success) { 514 if (success) { 515 mCurrentUserId = targetUserId; 516 } else { 517 Slog.w(TAG, "Failed to change user, still: " + mCurrentUserId); 518 } 519 } 520 }); 521 } 522 getCurrentUser()523 private int getCurrentUser() { 524 return mCurrentUserId; 525 } 526 527 @Override containsSensor(int sensorId)528 public boolean containsSensor(int sensorId) { 529 return mSensorProperties.sensorId == sensorId; 530 } 531 532 @Override 533 @NonNull getSensorProperties()534 public List<FingerprintSensorPropertiesInternal> getSensorProperties() { 535 final List<FingerprintSensorPropertiesInternal> properties = new ArrayList<>(); 536 properties.add(mSensorProperties); 537 return properties; 538 } 539 540 @Nullable 541 @Override getSensorProperties(int sensorId)542 public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId) { 543 return mSensorProperties; 544 } 545 546 @Override scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken)547 public void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) { 548 // Fingerprint2.1 keeps track of lockout in the framework. Let's just do it on the handler 549 // thread. 550 mHandler.post(() -> { 551 final FingerprintResetLockoutClient client = new FingerprintResetLockoutClient(mContext, 552 userId, mContext.getOpPackageName(), sensorId, 553 createLogger(BiometricsProtoEnums.ACTION_UNKNOWN, 554 BiometricsProtoEnums.CLIENT_UNKNOWN, 555 mAuthenticationStatsCollector), 556 mBiometricContext, mLockoutTracker); 557 mScheduler.scheduleClientMonitor(client); 558 }); 559 } 560 561 @Override scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token, @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName)562 public void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token, 563 @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName) { 564 mHandler.post(() -> { 565 final FingerprintGenerateChallengeClient client = 566 new FingerprintGenerateChallengeClient(mContext, mLazyDaemon, token, 567 new ClientMonitorCallbackConverter(receiver), userId, opPackageName, 568 mSensorProperties.sensorId, 569 createLogger(BiometricsProtoEnums.ACTION_UNKNOWN, 570 BiometricsProtoEnums.CLIENT_UNKNOWN, 571 mAuthenticationStatsCollector), 572 mBiometricContext); 573 mScheduler.scheduleClientMonitor(client); 574 }); 575 } 576 577 @Override scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token, @NonNull String opPackageName, long challenge)578 public void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token, 579 @NonNull String opPackageName, long challenge) { 580 mHandler.post(() -> { 581 final FingerprintRevokeChallengeClient client = new FingerprintRevokeChallengeClient( 582 mContext, mLazyDaemon, token, userId, opPackageName, 583 mSensorProperties.sensorId, 584 createLogger(BiometricsProtoEnums.ACTION_UNKNOWN, 585 BiometricsProtoEnums.CLIENT_UNKNOWN, 586 mAuthenticationStatsCollector), 587 mBiometricContext); 588 mScheduler.scheduleClientMonitor(client); 589 }); 590 } 591 592 @Override scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken, int userId, @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason)593 public long scheduleEnroll(int sensorId, @NonNull IBinder token, 594 @NonNull byte[] hardwareAuthToken, int userId, 595 @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName, 596 @FingerprintManager.EnrollReason int enrollReason) { 597 final long id = mRequestCounter.incrementAndGet(); 598 mHandler.post(() -> { 599 scheduleUpdateActiveUserWithoutHandler(userId); 600 601 final FingerprintEnrollClient client = new FingerprintEnrollClient(mContext, 602 mLazyDaemon, token, id, new ClientMonitorCallbackConverter(receiver), 603 userId, hardwareAuthToken, opPackageName, 604 FingerprintUtils.getLegacyInstance(mSensorId), ENROLL_TIMEOUT_SEC, 605 mSensorProperties.sensorId, 606 createLogger(BiometricsProtoEnums.ACTION_ENROLL, 607 BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector), 608 mBiometricContext, mUdfpsOverlayController, mSidefpsController, enrollReason); 609 mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() { 610 @Override 611 public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { 612 mBiometricStateCallback.onClientStarted(clientMonitor); 613 } 614 615 @Override 616 public void onBiometricAction(int action) { 617 mBiometricStateCallback.onBiometricAction(action); 618 } 619 620 @Override 621 public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, 622 boolean success) { 623 mBiometricStateCallback.onClientFinished(clientMonitor, success); 624 if (success) { 625 // Update authenticatorIds 626 scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId(), 627 true /* force */); 628 } 629 } 630 }); 631 }); 632 return id; 633 } 634 635 @Override cancelEnrollment(int sensorId, @NonNull IBinder token, long requestId)636 public void cancelEnrollment(int sensorId, @NonNull IBinder token, long requestId) { 637 mHandler.post(() -> mScheduler.cancelEnrollment(token, requestId)); 638 } 639 640 @Override scheduleFingerDetect(@onNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, @NonNull FingerprintAuthenticateOptions options, int statsClient)641 public long scheduleFingerDetect(@NonNull IBinder token, 642 @NonNull ClientMonitorCallbackConverter listener, 643 @NonNull FingerprintAuthenticateOptions options, 644 int statsClient) { 645 final long id = mRequestCounter.incrementAndGet(); 646 mHandler.post(() -> { 647 scheduleUpdateActiveUserWithoutHandler(options.getUserId()); 648 649 final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId); 650 final FingerprintDetectClient client = new FingerprintDetectClient(mContext, 651 mLazyDaemon, token, id, listener, options, 652 createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient, 653 mAuthenticationStatsCollector), 654 mBiometricContext, mUdfpsOverlayController, isStrongBiometric); 655 mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); 656 }); 657 658 return id; 659 } 660 661 @Override scheduleAuthenticate(@onNull IBinder token, long operationId, int cookie, @NonNull ClientMonitorCallbackConverter listener, @NonNull FingerprintAuthenticateOptions options, long requestId, boolean restricted, int statsClient, boolean allowBackgroundAuthentication)662 public void scheduleAuthenticate(@NonNull IBinder token, long operationId, 663 int cookie, @NonNull ClientMonitorCallbackConverter listener, 664 @NonNull FingerprintAuthenticateOptions options, 665 long requestId, boolean restricted, int statsClient, 666 boolean allowBackgroundAuthentication) { 667 mHandler.post(() -> { 668 scheduleUpdateActiveUserWithoutHandler(options.getUserId()); 669 670 final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId); 671 final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient( 672 mContext, mLazyDaemon, token, requestId, listener, operationId, 673 restricted, options, cookie, false /* requireConfirmation */, 674 createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient, 675 mAuthenticationStatsCollector), 676 mBiometricContext, isStrongBiometric, 677 mTaskStackListener, mLockoutTracker, 678 mUdfpsOverlayController, mSidefpsController, 679 allowBackgroundAuthentication, mSensorProperties, 680 Utils.getCurrentStrength(mSensorId)); 681 mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); 682 }); 683 } 684 685 @Override scheduleAuthenticate(@onNull IBinder token, long operationId, int cookie, @NonNull ClientMonitorCallbackConverter listener, @NonNull FingerprintAuthenticateOptions options, boolean restricted, int statsClient, boolean allowBackgroundAuthentication)686 public long scheduleAuthenticate(@NonNull IBinder token, long operationId, 687 int cookie, @NonNull ClientMonitorCallbackConverter listener, 688 @NonNull FingerprintAuthenticateOptions options, boolean restricted, int statsClient, 689 boolean allowBackgroundAuthentication) { 690 final long id = mRequestCounter.incrementAndGet(); 691 692 scheduleAuthenticate(token, operationId, cookie, listener, 693 options, id, restricted, statsClient, allowBackgroundAuthentication); 694 695 return id; 696 } 697 698 @Override startPreparedClient(int sensorId, int cookie)699 public void startPreparedClient(int sensorId, int cookie) { 700 mHandler.post(() -> mScheduler.startPreparedClient(cookie)); 701 } 702 703 @Override cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId)704 public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) { 705 Slog.d(TAG, "cancelAuthentication, sensorId: " + sensorId); 706 mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId)); 707 } 708 709 @Override scheduleRemove(int sensorId, @NonNull IBinder token, @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId, @NonNull String opPackageName)710 public void scheduleRemove(int sensorId, @NonNull IBinder token, 711 @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId, 712 @NonNull String opPackageName) { 713 mHandler.post(() -> { 714 scheduleUpdateActiveUserWithoutHandler(userId); 715 716 final FingerprintRemovalClient client = new FingerprintRemovalClient(mContext, 717 mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), fingerId, 718 userId, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId), 719 mSensorProperties.sensorId, 720 createLogger(BiometricsProtoEnums.ACTION_REMOVE, 721 BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector), 722 mBiometricContext, mAuthenticatorIds); 723 mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); 724 }); 725 } 726 727 @Override scheduleRemoveAll(int sensorId, @NonNull IBinder token, @NonNull IFingerprintServiceReceiver receiver, int userId, @NonNull String opPackageName)728 public void scheduleRemoveAll(int sensorId, @NonNull IBinder token, 729 @NonNull IFingerprintServiceReceiver receiver, int userId, 730 @NonNull String opPackageName) { 731 mHandler.post(() -> { 732 scheduleUpdateActiveUserWithoutHandler(userId); 733 734 // For IBiometricsFingerprint@2.1, remove(0) means remove all enrollments 735 final FingerprintRemovalClient client = new FingerprintRemovalClient(mContext, 736 mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), 737 0 /* fingerprintId */, userId, opPackageName, 738 FingerprintUtils.getLegacyInstance(mSensorId), 739 mSensorProperties.sensorId, 740 createLogger(BiometricsProtoEnums.ACTION_REMOVE, 741 BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector), 742 mBiometricContext, mAuthenticatorIds); 743 mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); 744 }); 745 } 746 scheduleInternalCleanup(int userId, @Nullable ClientMonitorCallback callback)747 private void scheduleInternalCleanup(int userId, 748 @Nullable ClientMonitorCallback callback) { 749 mHandler.post(() -> { 750 scheduleUpdateActiveUserWithoutHandler(userId); 751 752 final FingerprintInternalCleanupClient client = new FingerprintInternalCleanupClient( 753 mContext, mLazyDaemon, userId, mContext.getOpPackageName(), 754 mSensorProperties.sensorId, 755 createLogger(BiometricsProtoEnums.ACTION_ENUMERATE, 756 BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector), 757 mBiometricContext, 758 FingerprintUtils.getLegacyInstance(mSensorId), mAuthenticatorIds); 759 mScheduler.scheduleClientMonitor(client, callback); 760 }); 761 } 762 763 @Override scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback)764 public void scheduleInternalCleanup(int sensorId, int userId, 765 @Nullable ClientMonitorCallback callback) { 766 scheduleInternalCleanup(userId, new ClientMonitorCompositeCallback(callback, 767 mBiometricStateCallback)); 768 } 769 770 @Override scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments)771 public void scheduleInternalCleanup(int sensorId, int userId, 772 @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments) { 773 scheduleInternalCleanup(userId, new ClientMonitorCompositeCallback(callback, 774 mBiometricStateCallback)); 775 } 776 createLogger(int statsAction, int statsClient, AuthenticationStatsCollector authenticationStatsCollector)777 private BiometricLogger createLogger(int statsAction, int statsClient, 778 AuthenticationStatsCollector authenticationStatsCollector) { 779 return new BiometricLogger(mContext, BiometricsProtoEnums.MODALITY_FINGERPRINT, 780 statsAction, statsClient, authenticationStatsCollector); 781 } 782 783 @Override isHardwareDetected(int sensorId)784 public boolean isHardwareDetected(int sensorId) { 785 return getDaemon() != null; 786 } 787 788 @Override rename(int sensorId, int fingerId, int userId, @NonNull String name)789 public void rename(int sensorId, int fingerId, int userId, @NonNull String name) { 790 mHandler.post(() -> { 791 FingerprintUtils.getLegacyInstance(mSensorId) 792 .renameBiometricForUser(mContext, userId, fingerId, name); 793 }); 794 } 795 796 @Override 797 @NonNull getEnrolledFingerprints(int sensorId, int userId)798 public List<Fingerprint> getEnrolledFingerprints(int sensorId, int userId) { 799 return FingerprintUtils.getLegacyInstance(mSensorId).getBiometricsForUser(mContext, userId); 800 } 801 802 @Override hasEnrollments(int sensorId, int userId)803 public boolean hasEnrollments(int sensorId, int userId) { 804 return !getEnrolledFingerprints(sensorId, userId).isEmpty(); 805 } 806 807 @Override getLockoutModeForUser(int sensorId, int userId)808 @LockoutTracker.LockoutMode public int getLockoutModeForUser(int sensorId, int userId) { 809 return mLockoutTracker.getLockoutModeForUser(userId); 810 } 811 812 @Override getAuthenticatorId(int sensorId, int userId)813 public long getAuthenticatorId(int sensorId, int userId) { 814 return mAuthenticatorIds.getOrDefault(userId, 0L); 815 } 816 817 @Override onPointerDown(long requestId, int sensorId, PointerContext pc)818 public void onPointerDown(long requestId, int sensorId, PointerContext pc) { 819 mScheduler.getCurrentClientIfMatches(requestId, (client) -> { 820 if (!(client instanceof Udfps)) { 821 Slog.w(TAG, "onFingerDown received during client: " + client); 822 return; 823 } 824 ((Udfps) client).onPointerDown(pc); 825 }); 826 } 827 828 @Override onPointerUp(long requestId, int sensorId, PointerContext pc)829 public void onPointerUp(long requestId, int sensorId, PointerContext pc) { 830 mScheduler.getCurrentClientIfMatches(requestId, (client) -> { 831 if (!(client instanceof Udfps)) { 832 Slog.w(TAG, "onFingerDown received during client: " + client); 833 return; 834 } 835 ((Udfps) client).onPointerUp(pc); 836 }); 837 } 838 839 @Override onUdfpsUiEvent(@ingerprintManager.UdfpsUiEvent int event, long requestId, int sensorId)840 public void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event, long requestId, 841 int sensorId) { 842 mScheduler.getCurrentClientIfMatches(requestId, (client) -> { 843 if (!(client instanceof Udfps)) { 844 Slog.w(TAG, "onUdfpsUiEvent received during client: " + client); 845 return; 846 } 847 ((Udfps) client).onUdfpsUiEvent(event); 848 }); 849 } 850 851 @Override onPowerPressed()852 public void onPowerPressed() { 853 Slog.e(TAG, "onPowerPressed not supported for HIDL clients"); 854 } 855 856 @Override setUdfpsOverlayController(@onNull IUdfpsOverlayController controller)857 public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) { 858 mUdfpsOverlayController = controller; 859 } 860 861 @Override setSidefpsController(@onNull ISidefpsController controller)862 public void setSidefpsController(@NonNull ISidefpsController controller) { 863 mSidefpsController = controller; 864 } 865 866 @Override dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, boolean clearSchedulerBuffer)867 public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, 868 boolean clearSchedulerBuffer) { 869 final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES); 870 871 proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId); 872 proto.write(SensorStateProto.MODALITY, SensorStateProto.FINGERPRINT); 873 if (mSensorProperties.isAnyUdfpsType()) { 874 proto.write(SensorStateProto.MODALITY_FLAGS, SensorStateProto.FINGERPRINT_UDFPS); 875 } 876 proto.write(SensorStateProto.CURRENT_STRENGTH, 877 Utils.getCurrentStrength(mSensorProperties.sensorId)); 878 proto.write(SensorStateProto.SCHEDULER, mScheduler.dumpProtoState(clearSchedulerBuffer)); 879 880 for (UserInfo user : UserManager.get(mContext).getUsers()) { 881 final int userId = user.getUserHandle().getIdentifier(); 882 883 final long userToken = proto.start(SensorStateProto.USER_STATES); 884 proto.write(UserStateProto.USER_ID, userId); 885 proto.write(UserStateProto.NUM_ENROLLED, FingerprintUtils.getLegacyInstance(mSensorId) 886 .getBiometricsForUser(mContext, userId).size()); 887 proto.end(userToken); 888 } 889 890 proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_HARDWARE_AUTH_TOKEN, 891 mSensorProperties.resetLockoutRequiresHardwareAuthToken); 892 proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_CHALLENGE, 893 mSensorProperties.resetLockoutRequiresChallenge); 894 895 proto.end(sensorToken); 896 } 897 898 @Override dumpProtoMetrics(int sensorId, FileDescriptor fd)899 public void dumpProtoMetrics(int sensorId, FileDescriptor fd) { 900 PerformanceTracker tracker = 901 PerformanceTracker.getInstanceForSensorId(mSensorProperties.sensorId); 902 903 final ProtoOutputStream proto = new ProtoOutputStream(fd); 904 for (UserInfo user : UserManager.get(mContext).getUsers()) { 905 final int userId = user.getUserHandle().getIdentifier(); 906 907 final long userToken = proto.start(FingerprintServiceDumpProto.USERS); 908 909 proto.write(FingerprintUserStatsProto.USER_ID, userId); 910 proto.write(FingerprintUserStatsProto.NUM_FINGERPRINTS, 911 FingerprintUtils.getLegacyInstance(mSensorId) 912 .getBiometricsForUser(mContext, userId).size()); 913 914 // Normal fingerprint authentications (e.g. lockscreen) 915 long countsToken = proto.start(FingerprintUserStatsProto.NORMAL); 916 proto.write(PerformanceStatsProto.ACCEPT, tracker.getAcceptForUser(userId)); 917 proto.write(PerformanceStatsProto.REJECT, tracker.getRejectForUser(userId)); 918 proto.write(PerformanceStatsProto.ACQUIRE, tracker.getAcquireForUser(userId)); 919 proto.write(PerformanceStatsProto.LOCKOUT, tracker.getTimedLockoutForUser(userId)); 920 proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, 921 tracker.getPermanentLockoutForUser(userId)); 922 proto.end(countsToken); 923 924 // Statistics about secure fingerprint transactions (e.g. to unlock password 925 // storage, make secure purchases, etc.) 926 countsToken = proto.start(FingerprintUserStatsProto.CRYPTO); 927 proto.write(PerformanceStatsProto.ACCEPT, tracker.getAcceptCryptoForUser(userId)); 928 proto.write(PerformanceStatsProto.REJECT, tracker.getRejectCryptoForUser(userId)); 929 proto.write(PerformanceStatsProto.ACQUIRE, tracker.getAcquireCryptoForUser(userId)); 930 proto.write(PerformanceStatsProto.LOCKOUT, 0); // meaningless for crypto 931 proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, 0); // meaningless for crypto 932 proto.end(countsToken); 933 934 proto.end(userToken); 935 } 936 proto.flush(); 937 tracker.clear(); 938 } 939 940 @Override scheduleInvalidateAuthenticatorId(int sensorId, int userId, @NonNull IInvalidationCallback callback)941 public void scheduleInvalidateAuthenticatorId(int sensorId, int userId, 942 @NonNull IInvalidationCallback callback) { 943 // TODO (b/179101888): Remove this temporary workaround. 944 try { 945 callback.onCompleted(); 946 } catch (RemoteException e) { 947 Slog.e(TAG, "Failed to complete InvalidateAuthenticatorId"); 948 } 949 } 950 951 @Override dumpInternal(int sensorId, @NonNull PrintWriter pw)952 public void dumpInternal(int sensorId, @NonNull PrintWriter pw) { 953 PerformanceTracker performanceTracker = 954 PerformanceTracker.getInstanceForSensorId(mSensorProperties.sensorId); 955 956 JSONObject dump = new JSONObject(); 957 try { 958 dump.put("service", TAG); 959 dump.put("isUdfps", mIsUdfps); 960 dump.put("isPowerbuttonFps", mIsPowerbuttonFps); 961 962 JSONArray sets = new JSONArray(); 963 for (UserInfo user : UserManager.get(mContext).getUsers()) { 964 final int userId = user.getUserHandle().getIdentifier(); 965 final int N = FingerprintUtils.getLegacyInstance(mSensorId) 966 .getBiometricsForUser(mContext, userId).size(); 967 JSONObject set = new JSONObject(); 968 set.put("id", userId); 969 set.put("count", N); 970 set.put("accept", performanceTracker.getAcceptForUser(userId)); 971 set.put("reject", performanceTracker.getRejectForUser(userId)); 972 set.put("acquire", performanceTracker.getAcquireForUser(userId)); 973 set.put("lockout", performanceTracker.getTimedLockoutForUser(userId)); 974 set.put("permanentLockout", performanceTracker.getPermanentLockoutForUser(userId)); 975 // cryptoStats measures statistics about secure fingerprint transactions 976 // (e.g. to unlock password storage, make secure purchases, etc.) 977 set.put("acceptCrypto", performanceTracker.getAcceptCryptoForUser(userId)); 978 set.put("rejectCrypto", performanceTracker.getRejectCryptoForUser(userId)); 979 set.put("acquireCrypto", performanceTracker.getAcquireCryptoForUser(userId)); 980 sets.put(set); 981 } 982 983 dump.put("prints", sets); 984 } catch (JSONException e) { 985 Slog.e(TAG, "dump formatting failure", e); 986 } 987 pw.println(dump); 988 pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount()); 989 mScheduler.dump(pw); 990 } 991 setTestHalEnabled(boolean enabled)992 void setTestHalEnabled(boolean enabled) { 993 mTestHalEnabled = enabled; 994 } 995 996 @NonNull 997 @Override createTestSession(int sensorId, @NonNull ITestSessionCallback callback, @NonNull String opPackageName)998 public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, 999 @NonNull String opPackageName) { 1000 return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback, 1001 mBiometricStateCallback, this, mHalResultController); 1002 } 1003 } 1004