de-HIDL: Merge schedulers
1. Combine the two schedulers
2. Create a new thread for biometric scheduler operations
Test: atest BiometricSchedulerTest SensorTest
HidlToAidlSensorAdapterTest
Bug: 304604965
Change-Id: Id131715b80c6ef2986f1883c7bee5680001ef413
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 89b638b..89e08c1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors;
+import static com.android.server.biometrics.sensors.BiometricSchedulerOperation.STATE_STARTED;
+
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
@@ -28,6 +30,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -35,6 +38,7 @@
import com.android.modules.expresslog.Counter;
import com.android.server.biometrics.BiometricSchedulerProto;
import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.io.PrintWriter;
@@ -48,6 +52,7 @@
import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* A scheduler for biometric HAL operations. Maintains a queue of {@link BaseClientMonitor}
@@ -56,11 +61,16 @@
*
* We currently assume (and require) that each biometric sensor have its own instance of a
* {@link BiometricScheduler}.
+ *
+ * @param <T> Hal instance for starting the user.
+ * @param <U> Session associated with the current user id.
+ *
+ * TODO: (b/304604965) Update thread annotation when FLAGS_DE_HIDL is removed.
*/
@MainThread
-public class BiometricScheduler {
+public class BiometricScheduler<T, U> {
- private static final String BASE_TAG = "BiometricScheduler";
+ private static final String TAG = "BiometricScheduler";
// Number of recent operations to keep in our logs for dumpsys
protected static final int LOG_NUM_RECENT_OPERATIONS = 50;
@@ -89,30 +99,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface SensorType {}
- public static @SensorType int sensorTypeFromFingerprintProperties(
- @NonNull FingerprintSensorPropertiesInternal props) {
- if (props.isAnyUdfpsType()) {
- return SENSOR_TYPE_UDFPS;
- }
-
- return SENSOR_TYPE_FP_OTHER;
- }
-
- public static String sensorTypeToString(@SensorType int sensorType) {
- switch (sensorType) {
- case SENSOR_TYPE_UNKNOWN:
- return "Unknown";
- case SENSOR_TYPE_FACE:
- return "Face";
- case SENSOR_TYPE_UDFPS:
- return "Udfps";
- case SENSOR_TYPE_FP_OTHER:
- return "OtherFp";
- default:
- return "UnknownUnknown";
- }
- }
-
private static final class CrashState {
static final int NUM_ENTRIES = 10;
final String timestamp;
@@ -145,8 +131,8 @@
}
}
- @NonNull protected final String mBiometricTag;
- private final @SensorType int mSensorType;
+ @SensorType
+ private final int mSensorType;
@Nullable private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@NonNull private final IBiometricService mBiometricService;
@NonNull protected final Handler mHandler;
@@ -157,6 +143,43 @@
private int mTotalOperationsHandled;
private final int mRecentOperationsLimit;
@NonNull private final List<Integer> mRecentOperations;
+ @Nullable private StopUserClient<U> mStopUserClient;
+ @NonNull private Supplier<Integer> mCurrentUserRetriever;
+ @Nullable private UserSwitchProvider<T, U> mUserSwitchProvider;
+
+ private class UserSwitchClientCallback implements ClientMonitorCallback {
+ @NonNull private final BaseClientMonitor mOwner;
+
+ UserSwitchClientCallback(@NonNull BaseClientMonitor owner) {
+ mOwner = owner;
+ }
+
+ @Override
+ public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
+ mHandler.post(() -> {
+ Slog.d(TAG, "[Client finished] " + clientMonitor + ", success: " + success);
+
+ // Set mStopUserClient to null when StopUserClient fails. Otherwise it's possible
+ // for that the queue will wait indefinitely until the field is cleared.
+ if (clientMonitor instanceof StopUserClient<?>) {
+ if (!success) {
+ Slog.w(TAG, "StopUserClient failed(), is the HAL stuck? "
+ + "Clearing mStopUserClient");
+ }
+ mStopUserClient = null;
+ }
+ if (mCurrentOperation != null && mCurrentOperation.isFor(mOwner)) {
+ mCurrentOperation = null;
+ } else {
+ // can happen if the hal dies and is usually okay
+ // do not unset the current operation that may be newer
+ Slog.w(TAG, "operation is already null or different (reset?): "
+ + mCurrentOperation);
+ }
+ startNextOperationIfIdle();
+ });
+ }
+ }
// Internal callback, notified when an operation is complete. Notifies the requester
// that the operation is complete, before performing internal scheduler work (such as
@@ -164,26 +187,26 @@
private final ClientMonitorCallback mInternalCallback = new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
- Slog.d(getTag(), "[Started] " + clientMonitor);
+ Slog.d(TAG, "[Started] " + clientMonitor);
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
mHandler.post(() -> {
if (mCurrentOperation == null) {
- Slog.e(getTag(), "[Finishing] " + clientMonitor
+ Slog.e(TAG, "[Finishing] " + clientMonitor
+ " but current operation is null, success: " + success
+ ", possible lifecycle bug in clientMonitor implementation?");
return;
}
if (!mCurrentOperation.isFor(clientMonitor)) {
- Slog.e(getTag(), "[Ignoring Finish] " + clientMonitor + " does not match"
+ Slog.e(TAG, "[Ignoring Finish] " + clientMonitor + " does not match"
+ " current: " + mCurrentOperation);
return;
}
- Slog.d(getTag(), "[Finishing] " + clientMonitor + ", success: " + success);
+ Slog.d(TAG, "[Finishing] " + clientMonitor + ", success: " + success);
if (mGestureAvailabilityDispatcher != null) {
mGestureAvailabilityDispatcher.markSensorActive(
@@ -202,13 +225,11 @@
};
@VisibleForTesting
- public BiometricScheduler(@NonNull String tag,
- @NonNull Handler handler,
+ public BiometricScheduler(@NonNull Handler handler,
@SensorType int sensorType,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull IBiometricService biometricService,
int recentOperationsLimit) {
- mBiometricTag = tag;
mHandler = handler;
mSensorType = sensorType;
mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher;
@@ -219,49 +240,140 @@
mRecentOperations = new ArrayList<>();
}
+ @VisibleForTesting
+ public BiometricScheduler(@NonNull Handler handler,
+ @SensorType int sensorType,
+ @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull IBiometricService biometricService,
+ int recentOperationsLimit,
+ @NonNull Supplier<Integer> currentUserRetriever,
+ @Nullable UserSwitchProvider<T, U> userSwitchProvider) {
+ mHandler = handler;
+ mSensorType = sensorType;
+ mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher;
+ mPendingOperations = new ArrayDeque<>();
+ mBiometricService = biometricService;
+ mCrashStates = new ArrayDeque<>();
+ mRecentOperationsLimit = recentOperationsLimit;
+ mRecentOperations = new ArrayList<>();
+ mCurrentUserRetriever = currentUserRetriever;
+ mUserSwitchProvider = userSwitchProvider;
+ }
+
+ public BiometricScheduler(@NonNull Handler handler,
+ @SensorType int sensorType,
+ @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull Supplier<Integer> currentUserRetriever,
+ @NonNull UserSwitchProvider<T, U> userSwitchProvider) {
+ this(handler, sensorType, gestureAvailabilityDispatcher,
+ IBiometricService.Stub.asInterface(ServiceManager.getService(
+ Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS,
+ currentUserRetriever, userSwitchProvider);
+ }
+
/**
* Creates a new scheduler.
*
- * @param tag for the specific instance of the scheduler. Should be unique.
* @param sensorType the sensorType that this scheduler is handling.
* @param gestureAvailabilityDispatcher may be null if the sensor does not support gestures
* (such as fingerprint swipe).
*/
- public BiometricScheduler(@NonNull String tag,
- @SensorType int sensorType,
+ public BiometricScheduler(@SensorType int sensorType,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
- this(tag, new Handler(Looper.getMainLooper()), sensorType, gestureAvailabilityDispatcher,
+ this(new Handler(Looper.getMainLooper()), sensorType, gestureAvailabilityDispatcher,
IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE)),
LOG_NUM_RECENT_OPERATIONS);
}
+ /**
+ * Returns sensor type for a fingerprint sensor.
+ */
+ @SensorType
+ public static int sensorTypeFromFingerprintProperties(
+ @NonNull FingerprintSensorPropertiesInternal props) {
+ if (props.isAnyUdfpsType()) {
+ return SENSOR_TYPE_UDFPS;
+ }
+
+ return SENSOR_TYPE_FP_OTHER;
+ }
+
@VisibleForTesting
public ClientMonitorCallback getInternalCallback() {
return mInternalCallback;
}
- protected String getTag() {
- return BASE_TAG + "/" + mBiometricTag;
+ protected void startNextOperationIfIdle() {
+ if (Flags.deHidl()) {
+ startNextOperation();
+ } else {
+ startNextOperationIfIdleLegacy();
+ }
}
- protected void startNextOperationIfIdle() {
+ protected void startNextOperation() {
if (mCurrentOperation != null) {
- Slog.v(getTag(), "Not idle, current operation: " + mCurrentOperation);
+ Slog.v(TAG, "Not idle, current operation: " + mCurrentOperation);
return;
}
if (mPendingOperations.isEmpty()) {
- Slog.d(getTag(), "No operations, returning to idle");
+ Slog.d(TAG, "No operations, returning to idle");
+ return;
+ }
+
+ final int currentUserId = mCurrentUserRetriever.get();
+ final int nextUserId = mPendingOperations.getFirst().getTargetUserId();
+
+ if (nextUserId == currentUserId || mPendingOperations.getFirst().isStartUserOperation()) {
+ startNextOperationIfIdleLegacy();
+ } else if (currentUserId == UserHandle.USER_NULL && mUserSwitchProvider != null) {
+ final BaseClientMonitor startClient =
+ mUserSwitchProvider.getStartUserClient(nextUserId);
+ final UserSwitchClientCallback finishedCallback =
+ new UserSwitchClientCallback(startClient);
+
+ Slog.d(TAG, "[Starting User] " + startClient);
+ mCurrentOperation = new BiometricSchedulerOperation(
+ startClient, finishedCallback, STATE_STARTED);
+ startClient.start(finishedCallback);
+ } else if (mUserSwitchProvider != null) {
+ if (mStopUserClient != null) {
+ Slog.d(TAG, "[Waiting for StopUser] " + mStopUserClient);
+ } else {
+ mStopUserClient = mUserSwitchProvider
+ .getStopUserClient(currentUserId);
+ final UserSwitchClientCallback finishedCallback =
+ new UserSwitchClientCallback(mStopUserClient);
+
+ Slog.d(TAG, "[Stopping User] current: " + currentUserId
+ + ", next: " + nextUserId + ". " + mStopUserClient);
+ mCurrentOperation = new BiometricSchedulerOperation(
+ mStopUserClient, finishedCallback, STATE_STARTED);
+ mStopUserClient.start(finishedCallback);
+ }
+ } else {
+ Slog.e(TAG, "Cannot start next operation.");
+ }
+ }
+
+ protected void startNextOperationIfIdleLegacy() {
+ if (mCurrentOperation != null) {
+ Slog.v(TAG, "Not idle, current operation: " + mCurrentOperation);
+ return;
+ }
+ if (mPendingOperations.isEmpty()) {
+ Slog.d(TAG, "No operations, returning to idle");
return;
}
mCurrentOperation = mPendingOperations.poll();
- Slog.d(getTag(), "[Polled] " + mCurrentOperation);
+ Slog.d(TAG, "[Polled] " + mCurrentOperation);
// If the operation at the front of the queue has been marked for cancellation, send
// ERROR_CANCELED. No need to start this client.
if (mCurrentOperation.isMarkedCanceling()) {
- Slog.d(getTag(), "[Now Cancelling] " + mCurrentOperation);
+ Slog.d(TAG, "[Now Cancelling] " + mCurrentOperation);
mCurrentOperation.cancel(mHandler, mInternalCallback);
// Now we wait for the client to send its FinishCallback, which kicks off the next
// operation.
@@ -289,7 +401,7 @@
// Note down current length of queue
final int pendingOperationsLength = mPendingOperations.size();
final BiometricSchedulerOperation lastOperation = mPendingOperations.peekLast();
- Slog.e(getTag(), "[Unable To Start] " + mCurrentOperation
+ Slog.e(TAG, "[Unable To Start] " + mCurrentOperation
+ ". Last pending operation: " + lastOperation);
// Then for each operation currently in the pending queue at the time of this
@@ -298,10 +410,10 @@
for (int i = 0; i < pendingOperationsLength; i++) {
final BiometricSchedulerOperation operation = mPendingOperations.pollFirst();
if (operation != null) {
- Slog.w(getTag(), "[Aborting Operation] " + operation);
+ Slog.w(TAG, "[Aborting Operation] " + operation);
operation.abort();
} else {
- Slog.e(getTag(), "Null operation, index: " + i
+ Slog.e(TAG, "Null operation, index: " + i
+ ", expected length: " + pendingOperationsLength);
}
}
@@ -317,9 +429,9 @@
mBiometricService.onReadyForAuthentication(
mCurrentOperation.getClientMonitor().getRequestId(), cookie);
} catch (RemoteException e) {
- Slog.e(getTag(), "Remote exception when contacting BiometricService", e);
+ Slog.e(TAG, "Remote exception when contacting BiometricService", e);
}
- Slog.d(getTag(), "Waiting for cookie before starting: " + mCurrentOperation);
+ Slog.d(TAG, "Waiting for cookie before starting: " + mCurrentOperation);
}
}
@@ -338,14 +450,14 @@
*/
public void startPreparedClient(int cookie) {
if (mCurrentOperation == null) {
- Slog.e(getTag(), "Current operation is null");
+ Slog.e(TAG, "Current operation is null");
return;
}
if (mCurrentOperation.startWithCookie(mInternalCallback, cookie)) {
- Slog.d(getTag(), "[Started] Prepared client: " + mCurrentOperation);
+ Slog.d(TAG, "[Started] Prepared client: " + mCurrentOperation);
} else {
- Slog.e(getTag(), "[Unable To Start] Prepared client: " + mCurrentOperation);
+ Slog.e(TAG, "[Unable To Start] Prepared client: " + mCurrentOperation);
mCurrentOperation = null;
startNextOperationIfIdle();
}
@@ -374,13 +486,13 @@
if (clientMonitor.interruptsPrecedingClients()) {
for (BiometricSchedulerOperation operation : mPendingOperations) {
if (operation.markCanceling()) {
- Slog.d(getTag(), "New client, marking pending op as canceling: " + operation);
+ Slog.d(TAG, "New client, marking pending op as canceling: " + operation);
}
}
}
mPendingOperations.add(new BiometricSchedulerOperation(clientMonitor, clientCallback));
- Slog.d(getTag(), "[Added] " + clientMonitor
+ Slog.d(TAG, "[Added] " + clientMonitor
+ ", new queue size: " + mPendingOperations.size());
// If the new operation should interrupt preceding clients, and if the current operation is
@@ -389,7 +501,7 @@
&& mCurrentOperation != null
&& mCurrentOperation.isInterruptable()
&& mCurrentOperation.isStarted()) {
- Slog.d(getTag(), "[Cancelling Interruptable]: " + mCurrentOperation);
+ Slog.d(TAG, "[Cancelling Interruptable]: " + mCurrentOperation);
mCurrentOperation.cancel(mHandler, mInternalCallback);
} else {
startNextOperationIfIdle();
@@ -401,16 +513,16 @@
* @param token from the caller, should match the token passed in when requesting enrollment
*/
public void cancelEnrollment(IBinder token, long requestId) {
- Slog.d(getTag(), "cancelEnrollment, requestId: " + requestId);
+ Slog.d(TAG, "cancelEnrollment, requestId: " + requestId);
if (mCurrentOperation != null
&& canCancelEnrollOperation(mCurrentOperation, token, requestId)) {
- Slog.d(getTag(), "Cancelling enrollment op: " + mCurrentOperation);
+ Slog.d(TAG, "Cancelling enrollment op: " + mCurrentOperation);
mCurrentOperation.cancel(mHandler, mInternalCallback);
} else {
for (BiometricSchedulerOperation operation : mPendingOperations) {
if (canCancelEnrollOperation(operation, token, requestId)) {
- Slog.d(getTag(), "Cancelling pending enrollment op: " + operation);
+ Slog.d(TAG, "Cancelling pending enrollment op: " + operation);
operation.markCanceling();
}
}
@@ -423,16 +535,16 @@
* @param requestId the id returned when requesting authentication
*/
public void cancelAuthenticationOrDetection(IBinder token, long requestId) {
- Slog.d(getTag(), "cancelAuthenticationOrDetection, requestId: " + requestId);
+ Slog.d(TAG, "cancelAuthenticationOrDetection, requestId: " + requestId);
if (mCurrentOperation != null
&& canCancelAuthOperation(mCurrentOperation, token, requestId)) {
- Slog.d(getTag(), "Cancelling auth/detect op: " + mCurrentOperation);
+ Slog.d(TAG, "Cancelling auth/detect op: " + mCurrentOperation);
mCurrentOperation.cancel(mHandler, mInternalCallback);
} else {
for (BiometricSchedulerOperation operation : mPendingOperations) {
if (canCancelAuthOperation(operation, token, requestId)) {
- Slog.d(getTag(), "Cancelling pending auth/detect op: " + operation);
+ Slog.d(TAG, "Cancelling pending auth/detect op: " + operation);
operation.markCanceling();
}
}
@@ -504,11 +616,11 @@
mCurrentOperation != null ? mCurrentOperation.toString() : null,
pendingOperations);
mCrashStates.add(crashState);
- Slog.e(getTag(), "Recorded crash state: " + crashState.toString());
+ Slog.e(TAG, "Recorded crash state: " + crashState.toString());
}
public void dump(PrintWriter pw) {
- pw.println("Dump of BiometricScheduler " + getTag());
+ pw.println("Dump of BiometricScheduler " + TAG);
pw.println("Type: " + mSensorType);
pw.println("Current operation: " + mCurrentOperation);
pw.println("Pending operations: " + mPendingOperations.size());
@@ -548,7 +660,7 @@
* HAL dies.
*/
public void reset() {
- Slog.d(getTag(), "Resetting scheduler");
+ Slog.d(TAG, "Resetting scheduler");
mPendingOperations.clear();
mCurrentOperation = null;
}
@@ -562,11 +674,11 @@
return;
}
for (BiometricSchedulerOperation pendingOperation : mPendingOperations) {
- Slog.d(getTag(), "[Watchdog cancelling pending] "
+ Slog.d(TAG, "[Watchdog cancelling pending] "
+ pendingOperation.getClientMonitor());
pendingOperation.markCancelingForWatchdog();
}
- Slog.d(getTag(), "[Watchdog cancelling current] "
+ Slog.d(TAG, "[Watchdog cancelling current] "
+ mCurrentOperation.getClientMonitor());
mCurrentOperation.cancel(mHandler, getInternalCallback());
}
@@ -590,9 +702,23 @@
/**
* Handle stop user client when user switching occurs.
*/
- public void onUserStopped() {}
+ public void onUserStopped() {
+ if (mStopUserClient == null) {
+ Slog.e(TAG, "Unexpected onUserStopped");
+ return;
+ }
+
+ Slog.d(TAG, "[OnUserStopped]: " + mStopUserClient);
+ mStopUserClient.onUserStopped();
+ mStopUserClient = null;
+ }
public Handler getHandler() {
return mHandler;
}
+
+ @Nullable
+ public StopUserClient<?> getStopUserClient() {
+ return mStopUserClient;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java b/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java
index e8654dc..e01c4ec 100644
--- a/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java
@@ -30,7 +30,10 @@
/**
* Abstract class for stopping a user.
- * @param <T> Interface for stopping the user.
+ *
+ * @param <T> Session for stopping the user. It should be either an instance of
+ * {@link com.android.server.biometrics.sensors.fingerprint.aidl.AidlSession} or
+ * {@link com.android.server.biometrics.sensors.face.aidl.AidlSession}.
*/
public abstract class StopUserClient<T> extends HalClientMonitor<T> {
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
index 3753bbd..7ca10e3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
@@ -33,10 +33,14 @@
/**
* A user-aware scheduler that requests user-switches based on scheduled operation's targetUserId.
+ * TODO (b/304604965): Remove class when Flags.FLAG_DE_HIDL is removed.
+ *
+ * @param <T> Hal instance for starting the user.
+ * @param <U> Session associated with the current user id.
*/
-public class UserAwareBiometricScheduler extends BiometricScheduler {
+public class UserAwareBiometricScheduler<T, U> extends BiometricScheduler<T, U> {
- private static final String BASE_TAG = "UaBiometricScheduler";
+ private static final String TAG = "UaBiometricScheduler";
/**
* Interface to retrieve the owner's notion of the current userId. Note that even though
@@ -66,13 +70,13 @@
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
mHandler.post(() -> {
- Slog.d(getTag(), "[Client finished] " + clientMonitor + ", success: " + success);
+ Slog.d(TAG, "[Client finished] " + clientMonitor + ", success: " + success);
// Set mStopUserClient to null when StopUserClient fails. Otherwise it's possible
// for that the queue will wait indefinitely until the field is cleared.
if (clientMonitor instanceof StopUserClient<?>) {
if (!success) {
- Slog.w(getTag(), "StopUserClient failed(), is the HAL stuck? "
+ Slog.w(TAG, "StopUserClient failed(), is the HAL stuck? "
+ "Clearing mStopUserClient");
}
mStopUserClient = null;
@@ -82,7 +86,7 @@
} else {
// can happen if the hal dies and is usually okay
// do not unset the current operation that may be newer
- Slog.w(getTag(), "operation is already null or different (reset?): "
+ Slog.w(TAG, "operation is already null or different (reset?): "
+ mCurrentOperation);
}
startNextOperationIfIdle();
@@ -98,7 +102,7 @@
@NonNull IBiometricService biometricService,
@NonNull CurrentUserRetriever currentUserRetriever,
@NonNull UserSwitchCallback userSwitchCallback) {
- super(tag, handler, sensorType, gestureAvailabilityDispatcher, biometricService,
+ super(handler, sensorType, gestureAvailabilityDispatcher, biometricService,
LOG_NUM_RECENT_OPERATIONS);
mCurrentUserRetriever = currentUserRetriever;
@@ -117,18 +121,13 @@
}
@Override
- protected String getTag() {
- return BASE_TAG + "/" + mBiometricTag;
- }
-
- @Override
protected void startNextOperationIfIdle() {
if (mCurrentOperation != null) {
- Slog.v(getTag(), "Not idle, current operation: " + mCurrentOperation);
+ Slog.v(TAG, "Not idle, current operation: " + mCurrentOperation);
return;
}
if (mPendingOperations.isEmpty()) {
- Slog.d(getTag(), "No operations, returning to idle");
+ Slog.d(TAG, "No operations, returning to idle");
return;
}
@@ -143,20 +142,20 @@
final ClientFinishedCallback finishedCallback =
new ClientFinishedCallback(startClient);
- Slog.d(getTag(), "[Starting User] " + startClient);
+ Slog.d(TAG, "[Starting User] " + startClient);
mCurrentOperation = new BiometricSchedulerOperation(
startClient, finishedCallback, STATE_STARTED);
startClient.start(finishedCallback);
} else {
if (mStopUserClient != null) {
- Slog.d(getTag(), "[Waiting for StopUser] " + mStopUserClient);
+ Slog.d(TAG, "[Waiting for StopUser] " + mStopUserClient);
} else {
mStopUserClient = mUserSwitchCallback
.getStopUserClient(currentUserId);
final ClientFinishedCallback finishedCallback =
new ClientFinishedCallback(mStopUserClient);
- Slog.d(getTag(), "[Stopping User] current: " + currentUserId
+ Slog.d(TAG, "[Stopping User] current: " + currentUserId
+ ", next: " + nextUserId + ". " + mStopUserClient);
mCurrentOperation = new BiometricSchedulerOperation(
mStopUserClient, finishedCallback, STATE_STARTED);
@@ -168,11 +167,11 @@
@Override
public void onUserStopped() {
if (mStopUserClient == null) {
- Slog.e(getTag(), "Unexpected onUserStopped");
+ Slog.e(TAG, "Unexpected onUserStopped");
return;
}
- Slog.d(getTag(), "[OnUserStopped]: " + mStopUserClient);
+ Slog.d(TAG, "[OnUserStopped]: " + mStopUserClient);
mStopUserClient.onUserStopped();
mStopUserClient = null;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserSwitchProvider.java b/services/core/java/com/android/server/biometrics/sensors/UserSwitchProvider.java
new file mode 100644
index 0000000..bc5c55b
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/UserSwitchProvider.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors;
+
+import android.annotation.NonNull;
+
+/**
+ * Interface to get the appropriate start and stop user clients.
+ *
+ * @param <T> Hal instance for starting the user.
+ * @param <U> Session associated with the current user id.
+ */
+public interface UserSwitchProvider<T, U> {
+ @NonNull
+ StartUserClient<T, U> getStartUserClient(int newUserId);
+ @NonNull
+ StopUserClient<U> getStopUserClient(int userId);
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlSession.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlSession.java
index af46f44..3d61f99 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlSession.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlSession.java
@@ -53,12 +53,10 @@
mAidlResponseHandler = aidlResponseHandler;
}
- /** The underlying {@link ISession}. */
@NonNull public ISession getSession() {
return mSession;
}
- /** The user id associated with the session. */
public int getUserId() {
return mUserId;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 9fa15b8..e4ecf1a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -39,6 +39,7 @@
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
@@ -88,6 +89,8 @@
* Provider for a single instance of the {@link IFace} HAL.
*/
public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
+
+ private static final String TAG = "FaceProvider";
private static final int ENROLL_TIMEOUT_SEC = 75;
private boolean mTestHalEnabled;
@@ -159,7 +162,7 @@
@NonNull BiometricContext biometricContext,
boolean resetLockoutRequiresChallenge) {
this(context, biometricStateCallback, props, halInstanceName, lockoutResetDispatcher,
- biometricContext, null /* daemon */, resetLockoutRequiresChallenge,
+ biometricContext, null /* daemon */, getHandler(), resetLockoutRequiresChallenge,
false /* testHalEnabled */);
}
@@ -169,13 +172,19 @@
@NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull BiometricContext biometricContext,
- @Nullable IFace daemon, boolean resetLockoutRequiresChallenge,
+ @Nullable IFace daemon,
+ @NonNull Handler handler,
+ boolean resetLockoutRequiresChallenge,
boolean testHalEnabled) {
mContext = context;
mBiometricStateCallback = biometricStateCallback;
mHalInstanceName = halInstanceName;
mFaceSensors = new SensorList<>(ActivityManager.getService());
- mHandler = new Handler(Looper.getMainLooper());
+ if (Flags.deHidl()) {
+ mHandler = handler;
+ } else {
+ mHandler = new Handler(Looper.getMainLooper());
+ }
mUsageStats = new UsageStats(context);
mLockoutResetDispatcher = lockoutResetDispatcher;
mActivityTaskManager = ActivityTaskManager.getInstance();
@@ -189,6 +198,13 @@
initSensors(resetLockoutRequiresChallenge, props);
}
+ @NonNull
+ private static Handler getHandler() {
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ return new Handler(handlerThread.getLooper());
+ }
+
private void initAuthenticationBroadcastReceiver() {
new AuthenticationStatsBroadcastReceiver(
mContext,
@@ -230,8 +246,8 @@
prop.commonProps.maxEnrollmentsPerUser, componentInfo, prop.sensorType,
prop.supportsDetectInteraction, prop.halControlsPreview,
false /* resetLockoutRequiresChallenge */);
- final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this,
- mContext, mHandler, internalProp, mLockoutResetDispatcher,
+ final Sensor sensor = new Sensor(this,
+ mContext, mHandler, internalProp,
mBiometricContext);
sensor.init(mLockoutResetDispatcher, this);
final int userId = sensor.getLazySession().get() == null ? UserHandle.USER_NULL :
@@ -250,9 +266,8 @@
private void addHidlSensors(SensorProps prop, boolean resetLockoutRequiresChallenge) {
final int sensorId = prop.commonProps.sensorId;
- final Sensor sensor = new HidlToAidlSensorAdapter(getTag() + "/" + sensorId, this,
- mContext, mHandler, prop, mLockoutResetDispatcher,
- mBiometricContext, resetLockoutRequiresChallenge,
+ final Sensor sensor = new HidlToAidlSensorAdapter(this, mContext, mHandler, prop,
+ mLockoutResetDispatcher, mBiometricContext, resetLockoutRequiresChallenge,
() -> {
//TODO: update to make this testable
scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(),
@@ -279,8 +294,7 @@
private void addAidlSensors(SensorProps prop, boolean resetLockoutRequiresChallenge) {
final int sensorId = prop.commonProps.sensorId;
- final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext,
- mHandler, prop, mLockoutResetDispatcher, mBiometricContext,
+ final Sensor sensor = new Sensor(this, mContext, mHandler, prop, mBiometricContext,
resetLockoutRequiresChallenge);
sensor.init(mLockoutResetDispatcher, this);
final int userId = sensor.getLazySession().get() == null ? UserHandle.USER_NULL :
@@ -296,7 +310,7 @@
}
private String getTag() {
- return "FaceProvider/" + mHalInstanceName;
+ return TAG + "/" + mHalInstanceName;
}
boolean hasHalInstance() {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java
index 0110ae9..e5ae8e3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.biometrics.face.ISession;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -30,10 +31,10 @@
import java.util.function.Supplier;
-public class FaceStopUserClient extends StopUserClient<AidlSession> {
+public class FaceStopUserClient extends StopUserClient<ISession> {
private static final String TAG = "FaceStopUserClient";
- public FaceStopUserClient(@NonNull Context context, @NonNull Supplier<AidlSession> lazyDaemon,
+ public FaceStopUserClient(@NonNull Context context, @NonNull Supplier<ISession> lazyDaemon,
@Nullable IBinder token, int userId, int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull UserStoppedCallback callback) {
@@ -49,7 +50,7 @@
@Override
protected void startHalOperation() {
try {
- getFreshDaemon().getSession().close();
+ getFreshDaemon().close();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
getCallback().onClientFinished(this, false /* success */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 3e5c599..635e79a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -58,6 +58,7 @@
import com.android.server.biometrics.sensors.StartUserClient;
import com.android.server.biometrics.sensors.StopUserClient;
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
+import com.android.server.biometrics.sensors.UserSwitchProvider;
import com.android.server.biometrics.sensors.face.FaceUtils;
import java.util.ArrayList;
@@ -71,15 +72,16 @@
*/
public class Sensor {
+ private static final String TAG = "Sensor";
+
private boolean mTestHalEnabled;
- @NonNull private final String mTag;
@NonNull private final FaceProvider mProvider;
@NonNull private final Context mContext;
@NonNull private final IBinder mToken;
@NonNull private final Handler mHandler;
@NonNull private final FaceSensorPropertiesInternal mSensorProperties;
- @NonNull private BiometricScheduler mScheduler;
+ @NonNull private BiometricScheduler<IFace, ISession> mScheduler;
@Nullable private LockoutTracker mLockoutTracker;
@NonNull private final Map<Integer, Long> mAuthenticatorIds;
@@ -88,11 +90,9 @@
@NonNull BiometricContext mBiometricContext;
- Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
+ Sensor(@NonNull FaceProvider provider, @NonNull Context context,
@NonNull Handler handler, @NonNull FaceSensorPropertiesInternal sensorProperties,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull BiometricContext biometricContext, @Nullable AidlSession session) {
- mTag = tag;
+ @NonNull BiometricContext biometricContext) {
mProvider = provider;
mContext = context;
mToken = new Binder();
@@ -102,105 +102,135 @@
mAuthenticatorIds = new HashMap<>();
}
- Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
- @NonNull Handler handler, @NonNull FaceSensorPropertiesInternal sensorProperties,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull BiometricContext biometricContext) {
- this(tag, provider, context, handler, sensorProperties, lockoutResetDispatcher,
- biometricContext, null);
- }
-
- public Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
+ public Sensor(@NonNull FaceProvider provider, @NonNull Context context,
@NonNull Handler handler, @NonNull SensorProps prop,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull BiometricContext biometricContext,
boolean resetLockoutRequiresChallenge) {
- this(tag, provider, context, handler,
+ this(provider, context, handler,
getFaceSensorPropertiesInternal(prop, resetLockoutRequiresChallenge),
- lockoutResetDispatcher, biometricContext, null);
+ biometricContext);
}
/**
* Initialize biometric scheduler, lockout tracker and session for the sensor.
*/
- public void init(LockoutResetDispatcher lockoutResetDispatcher,
+ public void init(@NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull FaceProvider provider) {
+ if (Flags.deHidl()) {
+ setScheduler(getBiometricSchedulerForInit(lockoutResetDispatcher, provider));
+ } else {
+ setScheduler(getUserAwareBiometricSchedulerForInit(lockoutResetDispatcher, provider));
+ }
+ mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
+ mLockoutTracker = new LockoutCache();
+ }
+
+ private BiometricScheduler<IFace, ISession> getBiometricSchedulerForInit(
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull FaceProvider provider) {
+ return new BiometricScheduler<>(mHandler,
+ BiometricScheduler.SENSOR_TYPE_FACE,
+ null /* gestureAvailabilityDispatcher */,
+ () -> mCurrentSession != null ? mCurrentSession.getUserId() : UserHandle.USER_NULL,
+ new UserSwitchProvider<IFace, ISession>() {
+ @NonNull
+ @Override
+ public StopUserClient<ISession> getStopUserClient(int userId) {
+ return new FaceStopUserClient(mContext,
+ () -> mLazySession.get().getSession(), mToken, userId,
+ mSensorProperties.sensorId, BiometricLogger.ofUnknown(mContext),
+ mBiometricContext, () -> mCurrentSession = null);
+ }
+
+ @NonNull
+ @Override
+ public StartUserClient<IFace, ISession> getStartUserClient(int newUserId) {
+ final int sensorId = mSensorProperties.sensorId;
+ final AidlResponseHandler resultController = new AidlResponseHandler(
+ mContext, mScheduler, sensorId, newUserId,
+ mLockoutTracker, lockoutResetDispatcher,
+ mBiometricContext.getAuthSessionCoordinator(), () -> {
+ },
+ new AidlResponseHandler.AidlResponseHandlerCallback() {
+ @Override
+ public void onEnrollSuccess() {
+ mProvider.scheduleLoadAuthenticatorIdsForUser(sensorId,
+ newUserId);
+ mProvider.scheduleInvalidationRequest(sensorId,
+ newUserId);
+ }
+
+ @Override
+ public void onHardwareUnavailable() {
+ Slog.e(TAG, "Face sensor hardware unavailable.");
+ mCurrentSession = null;
+ }
+ });
+
+ return Sensor.this.getStartUserClient(resultController, sensorId,
+ newUserId, provider);
+ }
+ });
+ }
+
+ private UserAwareBiometricScheduler<IFace, ISession> getUserAwareBiometricSchedulerForInit(
+ LockoutResetDispatcher lockoutResetDispatcher,
FaceProvider provider) {
- mScheduler = new UserAwareBiometricScheduler(mTag,
+ return new UserAwareBiometricScheduler<>(TAG,
BiometricScheduler.SENSOR_TYPE_FACE, null /* gestureAvailabilityDispatcher */,
() -> mCurrentSession != null ? mCurrentSession.getUserId() : UserHandle.USER_NULL,
new UserAwareBiometricScheduler.UserSwitchCallback() {
@NonNull
@Override
- public StopUserClient<?> getStopUserClient(int userId) {
- return new FaceStopUserClient(mContext, mLazySession, mToken, userId,
- mSensorProperties.sensorId,
- BiometricLogger.ofUnknown(mContext), mBiometricContext,
- () -> mCurrentSession = null);
+ public StopUserClient<ISession> getStopUserClient(int userId) {
+ return new FaceStopUserClient(mContext,
+ () -> mLazySession.get().getSession(), mToken, userId,
+ mSensorProperties.sensorId, BiometricLogger.ofUnknown(mContext),
+ mBiometricContext, () -> mCurrentSession = null);
}
@NonNull
@Override
- public StartUserClient<?, ?> getStartUserClient(int newUserId) {
+ public StartUserClient<IFace, ISession> getStartUserClient(int newUserId) {
final int sensorId = mSensorProperties.sensorId;
+ final AidlResponseHandler resultController = new AidlResponseHandler(
+ mContext, mScheduler, sensorId, newUserId,
+ mLockoutTracker, lockoutResetDispatcher,
+ mBiometricContext.getAuthSessionCoordinator(), () -> {
+ Slog.e(TAG, "Face sensor hardware unavailable.");
+ mCurrentSession = null;
+ });
- final AidlResponseHandler resultController;
- if (Flags.deHidl()) {
- resultController = new AidlResponseHandler(
- mContext, mScheduler, sensorId, newUserId,
- mLockoutTracker, lockoutResetDispatcher,
- mBiometricContext.getAuthSessionCoordinator(), () -> {},
- new AidlResponseHandler.AidlResponseHandlerCallback() {
- @Override
- public void onEnrollSuccess() {
- mProvider.scheduleLoadAuthenticatorIdsForUser(sensorId,
- newUserId);
- mProvider.scheduleInvalidationRequest(sensorId,
- newUserId);
- }
-
- @Override
- public void onHardwareUnavailable() {
- Slog.e(mTag, "Face sensor hardware unavailable.");
- mCurrentSession = null;
- }
- });
- } else {
- resultController = new AidlResponseHandler(
- mContext, mScheduler, sensorId, newUserId,
- mLockoutTracker, lockoutResetDispatcher,
- mBiometricContext.getAuthSessionCoordinator(), () -> {
- Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
- mCurrentSession = null;
- });
- }
-
- final StartUserClient.UserStartedCallback<ISession> userStartedCallback =
- (userIdStarted, newSession, halInterfaceVersion) -> {
- Slog.d(mTag, "New session created for user: "
- + userIdStarted + " with hal version: "
- + halInterfaceVersion);
- mCurrentSession = new AidlSession(halInterfaceVersion,
- newSession, userIdStarted, resultController);
- if (FaceUtils.getLegacyInstance(sensorId)
- .isInvalidationInProgress(mContext, userIdStarted)) {
- Slog.w(mTag,
- "Scheduling unfinished invalidation request for "
- + "sensor: "
- + sensorId
- + ", user: " + userIdStarted);
- provider.scheduleInvalidationRequest(sensorId,
- userIdStarted);
- }
- };
-
- return new FaceStartUserClient(mContext, provider::getHalInstance,
- mToken, newUserId, mSensorProperties.sensorId,
- BiometricLogger.ofUnknown(mContext), mBiometricContext,
- resultController, userStartedCallback);
+ return Sensor.this.getStartUserClient(resultController, sensorId,
+ newUserId, provider);
}
});
- mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
- mLockoutTracker = new LockoutCache();
+ }
+
+ private FaceStartUserClient getStartUserClient(@NonNull AidlResponseHandler resultController,
+ int sensorId, int newUserId, @NonNull FaceProvider provider) {
+ final StartUserClient.UserStartedCallback<ISession> userStartedCallback =
+ (userIdStarted, newSession, halInterfaceVersion) -> {
+ Slog.d(TAG, "New face session created for user: "
+ + userIdStarted + " with hal version: "
+ + halInterfaceVersion);
+ mCurrentSession = new AidlSession(halInterfaceVersion,
+ newSession, userIdStarted, resultController);
+ if (FaceUtils.getLegacyInstance(sensorId)
+ .isInvalidationInProgress(mContext, userIdStarted)) {
+ Slog.w(TAG,
+ "Scheduling unfinished invalidation request for "
+ + "face sensor: "
+ + sensorId
+ + ", user: " + userIdStarted);
+ provider.scheduleInvalidationRequest(sensorId,
+ userIdStarted);
+ }
+ };
+
+ return new FaceStartUserClient(mContext, provider::getHalInstance, mToken, newUserId,
+ mSensorProperties.sensorId, BiometricLogger.ofUnknown(mContext), mBiometricContext,
+ resultController, userStartedCallback);
}
private static FaceSensorPropertiesInternal getFaceSensorPropertiesInternal(SensorProps prop,
@@ -213,13 +243,11 @@
info.softwareVersion));
}
}
- final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
+ return new FaceSensorPropertiesInternal(
prop.commonProps.sensorId, prop.commonProps.sensorStrength,
prop.commonProps.maxEnrollmentsPerUser, componentInfo, prop.sensorType,
prop.supportsDetectInteraction, prop.halControlsPreview,
resetLockoutRequiresChallenge);
-
- return internalProp;
}
@NonNull public Supplier<AidlSession> getLazySession() {
@@ -243,7 +271,7 @@
mProvider, this);
}
- @NonNull public BiometricScheduler getScheduler() {
+ @NonNull public BiometricScheduler<IFace, ISession> getScheduler() {
return mScheduler;
}
@@ -259,17 +287,17 @@
}
void setTestHalEnabled(boolean enabled) {
- Slog.w(mTag, "setTestHalEnabled: " + enabled);
+ Slog.w(TAG, "Face setTestHalEnabled: " + enabled);
if (enabled != mTestHalEnabled) {
// The framework should retrieve a new session from the HAL.
try {
if (mCurrentSession != null) {
// TODO(181984005): This should be scheduled instead of directly invoked
- Slog.d(mTag, "Closing old session");
+ Slog.d(TAG, "Closing old face session");
mCurrentSession.getSession().close();
}
} catch (RemoteException e) {
- Slog.e(mTag, "RemoteException", e);
+ Slog.e(TAG, "RemoteException", e);
}
mCurrentSession = null;
}
@@ -308,7 +336,7 @@
public void onBinderDied() {
final BaseClientMonitor client = mScheduler.getCurrentClient();
if (client != null && client.isInterruptable()) {
- Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
+ Slog.e(TAG, "Sending face hardware unavailable error for client: " + client);
final ErrorConsumer errorConsumer = (ErrorConsumer) client;
errorConsumer.onError(FaceManager.FACE_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index 46ce0b6..5337666 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -120,7 +120,7 @@
@NonNull private final FaceSensorPropertiesInternal mSensorProperties;
@NonNull private final BiometricStateCallback mBiometricStateCallback;
@NonNull private final Context mContext;
- @NonNull private final BiometricScheduler mScheduler;
+ @NonNull private final BiometricScheduler<IBiometricsFace, AidlSession> mScheduler;
@NonNull private final Handler mHandler;
@NonNull private final Supplier<IBiometricsFace> mLazyDaemon;
@NonNull private final LockoutHalImpl mLockoutTracker;
@@ -163,14 +163,15 @@
private final int mSensorId;
@NonNull private final Context mContext;
@NonNull private final Handler mHandler;
- @NonNull private final BiometricScheduler mScheduler;
+ @NonNull private final BiometricScheduler<IBiometricsFace, AidlSession> mScheduler;
@Nullable private Callback mCallback;
@NonNull private final LockoutHalImpl mLockoutTracker;
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
HalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler,
- @NonNull BiometricScheduler scheduler, @NonNull LockoutHalImpl lockoutTracker,
+ @NonNull BiometricScheduler<IBiometricsFace, AidlSession> scheduler,
+ @NonNull LockoutHalImpl lockoutTracker,
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
mSensorId = sensorId;
mContext = context;
@@ -352,7 +353,7 @@
@NonNull FaceSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull Handler handler,
- @NonNull BiometricScheduler scheduler,
+ @NonNull BiometricScheduler<IBiometricsFace, AidlSession> scheduler,
@NonNull BiometricContext biometricContext) {
mSensorProperties = sensorProps;
mContext = context;
@@ -395,7 +396,8 @@
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
final Handler handler = new Handler(Looper.getMainLooper());
return new Face10(context, biometricStateCallback, sensorProps, lockoutResetDispatcher,
- handler, new BiometricScheduler(TAG, BiometricScheduler.SENSOR_TYPE_FACE,
+ handler, new BiometricScheduler<>(
+ BiometricScheduler.SENSOR_TYPE_FACE,
null /* gestureAvailabilityTracker */),
BiometricContext.getInstance(context));
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapter.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapter.java
index 6355cb5..a004cae4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapter.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.hardware.biometrics.face.ISession;
import android.hardware.biometrics.face.SensorProps;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.os.Handler;
@@ -67,8 +68,7 @@
};
private LockoutHalImpl mLockoutTracker;
- public HidlToAidlSensorAdapter(@NonNull String tag,
- @NonNull FaceProvider provider,
+ public HidlToAidlSensorAdapter(@NonNull FaceProvider provider,
@NonNull Context context,
@NonNull Handler handler,
@NonNull SensorProps prop,
@@ -76,15 +76,14 @@
@NonNull BiometricContext biometricContext,
boolean resetLockoutRequiresChallenge,
@NonNull Runnable internalCleanupAndGetFeatureRunnable) {
- this(tag, provider, context, handler, prop, lockoutResetDispatcher, biometricContext,
+ this(provider, context, handler, prop, lockoutResetDispatcher, biometricContext,
resetLockoutRequiresChallenge, internalCleanupAndGetFeatureRunnable,
new AuthSessionCoordinator(), null /* daemon */,
null /* onEnrollSuccessCallback */);
}
@VisibleForTesting
- HidlToAidlSensorAdapter(@NonNull String tag,
- @NonNull FaceProvider provider,
+ HidlToAidlSensorAdapter(@NonNull FaceProvider provider,
@NonNull Context context,
@NonNull Handler handler,
@NonNull SensorProps prop,
@@ -95,7 +94,7 @@
@NonNull AuthSessionCoordinator authSessionCoordinator,
@Nullable IBiometricsFace daemon,
@Nullable AidlResponseHandler.AidlResponseHandlerCallback aidlResponseHandlerCallback) {
- super(tag, provider, context, handler, prop, lockoutResetDispatcher, biometricContext,
+ super(provider, context, handler, prop, biometricContext,
resetLockoutRequiresChallenge);
mInternalCleanupAndGetFeatureRunnable = internalCleanupAndGetFeatureRunnable;
mFaceProvider = provider;
@@ -124,7 +123,7 @@
@Override
public void serviceDied(long cookie) {
- Slog.d(TAG, "HAL died.");
+ Slog.d(TAG, "Face HAL died.");
mDaemon = null;
}
@@ -140,10 +139,12 @@
}
@Override
- public void init(LockoutResetDispatcher lockoutResetDispatcher,
- FaceProvider provider) {
- setScheduler(new BiometricScheduler(TAG, BiometricScheduler.SENSOR_TYPE_FACE,
- null /* gestureAvailabilityTracker */));
+ public void init(@NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull FaceProvider provider) {
+ setScheduler(new BiometricScheduler<ISession, AidlSession>(getHandler(),
+ BiometricScheduler.SENSOR_TYPE_FACE,
+ null /* gestureAvailabilityTracker */, () -> mCurrentUserId,
+ null /* userSwitchProvider */));
setLazySession(this::getSession);
mLockoutTracker = new LockoutHalImpl();
}
@@ -188,7 +189,7 @@
return mDaemon;
}
- Slog.d(TAG, "Daemon was null, reconnecting, current operation: "
+ Slog.d(TAG, "Face daemon was null, reconnecting, current operation: "
+ getScheduler().getCurrentClient());
try {
@@ -213,7 +214,7 @@
}
@VisibleForTesting void handleUserChanged(int newUserId) {
- Slog.d(TAG, "User changed. Current user is " + newUserId);
+ Slog.d(TAG, "User changed. Current user for face sensor is " + newUserId);
mSession = null;
mCurrentUserId = newUserId;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapter.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapter.java
index 5daf2d4..fa95361 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapter.java
@@ -282,7 +282,7 @@
@Override
public ICancellationSignal enrollWithOptions(FaceEnrollOptions options) {
- //Unsupported in HIDL
+ Slog.e(TAG, "enrollWithOptions unsupported in HIDL");
return null;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlSession.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlSession.java
index 8ff105b..0d4dac0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlSession.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlSession.java
@@ -51,12 +51,10 @@
mAidlResponseHandler = aidlResponseHandler;
}
- /** The underlying {@link ISession}. */
@NonNull public ISession getSession() {
return mSession;
}
- /** The user id associated with the session. */
public int getUserId() {
return mUserId;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 88a11d9..c0388d1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -46,6 +46,7 @@
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Binder;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
@@ -102,6 +103,8 @@
@SuppressWarnings("deprecation")
public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvider {
+ private static final String TAG = "FingerprintProvider";
+
private boolean mTestHalEnabled;
@NonNull
@@ -172,7 +175,7 @@
boolean resetLockoutRequiresHardwareAuthToken) {
this(context, biometricStateCallback, authenticationStateListeners, props, halInstanceName,
lockoutResetDispatcher, gestureAvailabilityDispatcher, biometricContext,
- null /* daemon */, resetLockoutRequiresHardwareAuthToken,
+ null /* daemon */, getHandler(), resetLockoutRequiresHardwareAuthToken,
false /* testHalEnabled */);
}
@@ -184,6 +187,7 @@
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext,
@Nullable IFingerprint daemon,
+ @NonNull Handler handler,
boolean resetLockoutRequiresHardwareAuthToken,
boolean testHalEnabled) {
mContext = context;
@@ -191,7 +195,11 @@
mAuthenticationStateListeners = authenticationStateListeners;
mHalInstanceName = halInstanceName;
mFingerprintSensors = new SensorList<>(ActivityManager.getService());
- mHandler = new Handler(Looper.getMainLooper());
+ if (Flags.deHidl()) {
+ mHandler = handler;
+ } else {
+ mHandler = new Handler(Looper.getMainLooper());
+ }
mLockoutResetDispatcher = lockoutResetDispatcher;
mActivityTaskManager = ActivityTaskManager.getInstance();
mTaskStackListener = new BiometricTaskStackListener();
@@ -204,6 +212,13 @@
initSensors(resetLockoutRequiresHardwareAuthToken, props, gestureAvailabilityDispatcher);
}
+ @NonNull
+ private static Handler getHandler() {
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ return new Handler(handlerThread.getLooper());
+ }
+
private void initAuthenticationBroadcastReceiver() {
new AuthenticationStatsBroadcastReceiver(
mContext,
@@ -262,11 +277,9 @@
location.sensorLocationY,
location.sensorRadius))
.collect(Collectors.toList()));
- final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext,
- mHandler, internalProp, mLockoutResetDispatcher,
- gestureAvailabilityDispatcher, mBiometricContext);
- sensor.init(gestureAvailabilityDispatcher,
- mLockoutResetDispatcher);
+ final Sensor sensor = new Sensor(this, mContext, mHandler, internalProp,
+ mBiometricContext);
+ sensor.init(gestureAvailabilityDispatcher, mLockoutResetDispatcher);
final int sessionUserId =
sensor.getLazySession().get() == null ? UserHandle.USER_NULL :
sensor.getLazySession().get().getUserId();
@@ -286,10 +299,8 @@
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
boolean resetLockoutRequiresHardwareAuthToken) {
final int sensorId = prop.commonProps.sensorId;
- final Sensor sensor = new HidlToAidlSensorAdapter(getTag() + "/"
- + sensorId, this, mContext, mHandler,
- prop, mLockoutResetDispatcher, gestureAvailabilityDispatcher,
- mBiometricContext, resetLockoutRequiresHardwareAuthToken,
+ final Sensor sensor = new HidlToAidlSensorAdapter(this, mContext, mHandler, prop,
+ mLockoutResetDispatcher, mBiometricContext, resetLockoutRequiresHardwareAuthToken,
() -> scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(),
null /* callback */));
sensor.init(gestureAvailabilityDispatcher, mLockoutResetDispatcher);
@@ -307,14 +318,11 @@
private void addAidlSensors(@NonNull SensorProps prop,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
- List<SensorLocationInternal> workaroundLocations,
+ @NonNull List<SensorLocationInternal> workaroundLocations,
boolean resetLockoutRequiresHardwareAuthToken) {
final int sensorId = prop.commonProps.sensorId;
- final Sensor sensor = new Sensor(getTag() + "/" + sensorId,
- this, mContext, mHandler,
- prop, mLockoutResetDispatcher, gestureAvailabilityDispatcher,
- mBiometricContext, workaroundLocations,
- resetLockoutRequiresHardwareAuthToken);
+ final Sensor sensor = new Sensor(this, mContext, mHandler, prop, mBiometricContext,
+ workaroundLocations, resetLockoutRequiresHardwareAuthToken);
sensor.init(gestureAvailabilityDispatcher, mLockoutResetDispatcher);
final int sessionUserId = sensor.getLazySession().get() == null ? UserHandle.USER_NULL :
sensor.getLazySession().get().getUserId();
@@ -329,7 +337,7 @@
}
private String getTag() {
- return "FingerprintProvider/" + mHalInstanceName;
+ return TAG + "/" + mHalInstanceName;
}
boolean hasHalInstance() {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java
index 2cc1879..394f045 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.biometrics.fingerprint.ISession;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -30,11 +31,11 @@
import java.util.function.Supplier;
-public class FingerprintStopUserClient extends StopUserClient<AidlSession> {
+public class FingerprintStopUserClient extends StopUserClient<ISession> {
private static final String TAG = "FingerprintStopUserClient";
public FingerprintStopUserClient(@NonNull Context context,
- @NonNull Supplier<AidlSession> lazyDaemon, @Nullable IBinder token, int userId,
+ @NonNull Supplier<ISession> lazyDaemon, @Nullable IBinder token, int userId,
int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull UserStoppedCallback callback) {
@@ -50,7 +51,7 @@
@Override
protected void startHalOperation() {
try {
- getFreshDaemon().getSession().close();
+ getFreshDaemon().close();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
getCallback().onClientFinished(this, false /* success */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index dd887bb..af88c62 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -59,6 +59,7 @@
import com.android.server.biometrics.sensors.StartUserClient;
import com.android.server.biometrics.sensors.StopUserClient;
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
+import com.android.server.biometrics.sensors.UserSwitchProvider;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
@@ -77,15 +78,16 @@
@SuppressWarnings("deprecation")
public class Sensor {
+ private static final String TAG = "Sensor";
+
private boolean mTestHalEnabled;
- @NonNull private final String mTag;
@NonNull private final FingerprintProvider mProvider;
@NonNull private final Context mContext;
@NonNull private final IBinder mToken;
@NonNull private final Handler mHandler;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
- @NonNull private BiometricScheduler mScheduler;
+ @NonNull private BiometricScheduler<IFingerprint, ISession> mScheduler;
@NonNull private LockoutTracker mLockoutTracker;
@NonNull private final Map<Integer, Long> mAuthenticatorIds;
@NonNull private final BiometricContext mBiometricContext;
@@ -93,13 +95,10 @@
@Nullable AidlSession mCurrentSession;
@NonNull private Supplier<AidlSession> mLazySession;
- public Sensor(@NonNull String tag, @NonNull FingerprintProvider provider,
+ public Sensor(@NonNull FingerprintProvider provider,
@NonNull Context context, @NonNull Handler handler,
@NonNull FingerprintSensorPropertiesInternal sensorProperties,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext, AidlSession session) {
- mTag = tag;
mProvider = provider;
mContext = context;
mToken = new Binder();
@@ -110,41 +109,52 @@
mCurrentSession = session;
}
- Sensor(@NonNull String tag, @NonNull FingerprintProvider provider, @NonNull Context context,
+ Sensor(@NonNull FingerprintProvider provider, @NonNull Context context,
@NonNull Handler handler, @NonNull FingerprintSensorPropertiesInternal sensorProperties,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext) {
- this(tag, provider, context, handler, sensorProperties, lockoutResetDispatcher,
- gestureAvailabilityDispatcher, biometricContext, null);
+ this(provider, context, handler, sensorProperties,
+ biometricContext, null);
}
- Sensor(@NonNull String tag, @NonNull FingerprintProvider provider, @NonNull Context context,
+ Sensor(@NonNull FingerprintProvider provider, @NonNull Context context,
@NonNull Handler handler, @NonNull SensorProps sensorProp,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext,
@NonNull List<SensorLocationInternal> workaroundLocation,
boolean resetLockoutRequiresHardwareAuthToken) {
- this(tag, provider, context, handler, getFingerprintSensorPropertiesInternal(sensorProp,
+ this(provider, context, handler, getFingerprintSensorPropertiesInternal(sensorProp,
workaroundLocation, resetLockoutRequiresHardwareAuthToken),
- lockoutResetDispatcher, gestureAvailabilityDispatcher, biometricContext, null);
+ biometricContext, null);
}
/**
* Initialize biometric scheduler, lockout tracker and session for the sensor.
*/
- public void init(GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
- LockoutResetDispatcher lockoutResetDispatcher) {
- mScheduler = new UserAwareBiometricScheduler(mTag,
+ public void init(@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ if (Flags.deHidl()) {
+ setScheduler(getBiometricSchedulerForInit(gestureAvailabilityDispatcher,
+ lockoutResetDispatcher));
+ } else {
+ setScheduler(getUserAwareBiometricSchedulerForInit(gestureAvailabilityDispatcher,
+ lockoutResetDispatcher));
+ }
+ mLockoutTracker = new LockoutCache();
+ mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
+ }
+
+ private BiometricScheduler<IFingerprint, ISession> getBiometricSchedulerForInit(
+ @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ return new BiometricScheduler<>(mHandler,
BiometricScheduler.sensorTypeFromFingerprintProperties(mSensorProperties),
gestureAvailabilityDispatcher,
() -> mCurrentSession != null ? mCurrentSession.getUserId() : UserHandle.USER_NULL,
- new UserAwareBiometricScheduler.UserSwitchCallback() {
+ new UserSwitchProvider<IFingerprint, ISession>() {
@NonNull
@Override
- public StopUserClient<?> getStopUserClient(int userId) {
- return new FingerprintStopUserClient(mContext, mLazySession, mToken,
+ public StopUserClient<ISession> getStopUserClient(int userId) {
+ return new FingerprintStopUserClient(mContext,
+ () -> mLazySession.get().getSession(), mToken,
userId, mSensorProperties.sensorId,
BiometricLogger.ofUnknown(mContext), mBiometricContext,
() -> mCurrentSession = null);
@@ -152,69 +162,100 @@
@NonNull
@Override
- public StartUserClient<?, ?> getStartUserClient(int newUserId) {
+ public StartUserClient<IFingerprint, ISession> getStartUserClient(
+ int newUserId) {
final int sensorId = mSensorProperties.sensorId;
-
- final AidlResponseHandler resultController;
-
- if (Flags.deHidl()) {
- resultController = new AidlResponseHandler(
- mContext, mScheduler, sensorId, newUserId,
- mLockoutTracker, lockoutResetDispatcher,
- mBiometricContext.getAuthSessionCoordinator(), () -> {},
- new AidlResponseHandler.AidlResponseHandlerCallback() {
- @Override
- public void onEnrollSuccess() {
- mProvider.scheduleLoadAuthenticatorIdsForUser(sensorId,
- newUserId);
- mProvider.scheduleInvalidationRequest(sensorId,
- newUserId);
- }
-
- @Override
- public void onHardwareUnavailable() {
- Slog.e(mTag,
- "Fingerprint sensor hardware unavailable.");
- mCurrentSession = null;
- }
- });
- } else {
- resultController = new AidlResponseHandler(
- mContext, mScheduler, sensorId, newUserId,
- mLockoutTracker, lockoutResetDispatcher,
- mBiometricContext.getAuthSessionCoordinator(), () -> {
- Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
- mCurrentSession = null;
- });
- }
-
- final StartUserClient.UserStartedCallback<ISession> userStartedCallback =
- (userIdStarted, newSession, halInterfaceVersion) -> {
- Slog.d(mTag, "New session created for user: "
- + userIdStarted + " with hal version: "
- + halInterfaceVersion);
- mCurrentSession = new AidlSession(halInterfaceVersion,
- newSession, userIdStarted, resultController);
- if (FingerprintUtils.getInstance(sensorId)
- .isInvalidationInProgress(mContext, userIdStarted)) {
- Slog.w(mTag,
- "Scheduling unfinished invalidation request for "
- + "sensor: "
- + sensorId
- + ", user: " + userIdStarted);
+ final AidlResponseHandler resultController = new AidlResponseHandler(
+ mContext, mScheduler, sensorId, newUserId,
+ mLockoutTracker, lockoutResetDispatcher,
+ mBiometricContext.getAuthSessionCoordinator(), () -> {},
+ new AidlResponseHandler.AidlResponseHandlerCallback() {
+ @Override
+ public void onEnrollSuccess() {
+ mProvider.scheduleLoadAuthenticatorIdsForUser(sensorId,
+ newUserId);
mProvider.scheduleInvalidationRequest(sensorId,
- userIdStarted);
+ newUserId);
}
- };
- return new FingerprintStartUserClient(mContext, mProvider::getHalInstance,
- mToken, newUserId, mSensorProperties.sensorId,
- BiometricLogger.ofUnknown(mContext), mBiometricContext,
- resultController, userStartedCallback);
+ @Override
+ public void onHardwareUnavailable() {
+ Slog.e(TAG,
+ "Fingerprint sensor hardware unavailable.");
+ mCurrentSession = null;
+ }
+ });
+
+ return Sensor.this.getStartUserClient(resultController, sensorId,
+ newUserId);
}
});
- mLockoutTracker = new LockoutCache();
- mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
+ }
+
+ private UserAwareBiometricScheduler<ISession, AidlSession>
+ getUserAwareBiometricSchedulerForInit(
+ GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ LockoutResetDispatcher lockoutResetDispatcher) {
+ return new UserAwareBiometricScheduler<>(TAG,
+ BiometricScheduler.sensorTypeFromFingerprintProperties(mSensorProperties),
+ gestureAvailabilityDispatcher,
+ () -> mCurrentSession != null ? mCurrentSession.getUserId() : UserHandle.USER_NULL,
+ new UserAwareBiometricScheduler.UserSwitchCallback() {
+ @NonNull
+ @Override
+ public StopUserClient<ISession> getStopUserClient(int userId) {
+ return new FingerprintStopUserClient(mContext,
+ () -> mLazySession.get().getSession(), mToken,
+ userId, mSensorProperties.sensorId,
+ BiometricLogger.ofUnknown(mContext), mBiometricContext,
+ () -> mCurrentSession = null);
+ }
+
+ @NonNull
+ @Override
+ public StartUserClient<IFingerprint, ISession> getStartUserClient(
+ int newUserId) {
+ final int sensorId = mSensorProperties.sensorId;
+
+ final AidlResponseHandler resultController = new AidlResponseHandler(
+ mContext, mScheduler, sensorId, newUserId,
+ mLockoutTracker, lockoutResetDispatcher,
+ mBiometricContext.getAuthSessionCoordinator(), () -> {
+ Slog.e(TAG, "Fingerprint hardware unavailable.");
+ mCurrentSession = null;
+ });
+
+ return Sensor.this.getStartUserClient(resultController, sensorId,
+ newUserId);
+ }
+ });
+ }
+
+ private FingerprintStartUserClient getStartUserClient(AidlResponseHandler resultController,
+ int sensorId, int newUserId) {
+ final StartUserClient.UserStartedCallback<ISession> userStartedCallback =
+ (userIdStarted, newSession, halInterfaceVersion) -> {
+ Slog.d(TAG, "New fingerprint session created for user: "
+ + userIdStarted + " with hal version: "
+ + halInterfaceVersion);
+ mCurrentSession = new AidlSession(halInterfaceVersion,
+ newSession, userIdStarted, resultController);
+ if (FingerprintUtils.getInstance(sensorId)
+ .isInvalidationInProgress(mContext, userIdStarted)) {
+ Slog.w(TAG,
+ "Scheduling unfinished invalidation request for "
+ + "fingerprint sensor: "
+ + sensorId
+ + ", user: " + userIdStarted);
+ mProvider.scheduleInvalidationRequest(sensorId,
+ userIdStarted);
+ }
+ };
+
+ return new FingerprintStartUserClient(mContext, mProvider::getHalInstance,
+ mToken, newUserId, mSensorProperties.sensorId,
+ BiometricLogger.ofUnknown(mContext), mBiometricContext,
+ resultController, userStartedCallback);
}
protected static FingerprintSensorPropertiesInternal getFingerprintSensorPropertiesInternal(
@@ -267,7 +308,7 @@
biometricStateCallback, mProvider, this);
}
- @NonNull public BiometricScheduler getScheduler() {
+ @NonNull public BiometricScheduler<IFingerprint, ISession> getScheduler() {
return mScheduler;
}
@@ -283,17 +324,17 @@
}
void setTestHalEnabled(boolean enabled) {
- Slog.w(mTag, "setTestHalEnabled: " + enabled);
+ Slog.w(TAG, "Fingerprint setTestHalEnabled: " + enabled);
if (enabled != mTestHalEnabled) {
// The framework should retrieve a new session from the HAL.
try {
if (mCurrentSession != null) {
// TODO(181984005): This should be scheduled instead of directly invoked
- Slog.d(mTag, "Closing old session");
+ Slog.d(TAG, "Closing old fingerprint session");
mCurrentSession.getSession().close();
}
} catch (RemoteException e) {
- Slog.e(mTag, "RemoteException", e);
+ Slog.e(TAG, "RemoteException", e);
}
mCurrentSession = null;
}
@@ -335,7 +376,7 @@
public void onBinderDied() {
final BaseClientMonitor client = mScheduler.getCurrentClient();
if (client instanceof ErrorConsumer) {
- Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
+ Slog.e(TAG, "Sending fingerprint hardware unavailable error for client: " + client);
final ErrorConsumer errorConsumer = (ErrorConsumer) client;
errorConsumer.onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index d3cecd0..4accf8f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -119,7 +119,7 @@
@NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
private final ActivityTaskManager mActivityTaskManager;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
- private final BiometricScheduler mScheduler;
+ private final BiometricScheduler<IBiometricsFingerprint, AidlSession> mScheduler;
private final Handler mHandler;
private final LockoutResetDispatcher mLockoutResetDispatcher;
private final LockoutFrameworkImpl mLockoutTracker;
@@ -198,11 +198,11 @@
private final int mSensorId;
@NonNull private final Context mContext;
@NonNull final Handler mHandler;
- @NonNull final BiometricScheduler mScheduler;
+ @NonNull final BiometricScheduler<IBiometricsFingerprint, AidlSession> mScheduler;
@Nullable private Callback mCallback;
HalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler,
- @NonNull BiometricScheduler scheduler) {
+ @NonNull BiometricScheduler<IBiometricsFingerprint, AidlSession> scheduler) {
mSensorId = sensorId;
mContext = context;
mHandler = handler;
@@ -336,7 +336,7 @@
@NonNull BiometricStateCallback biometricStateCallback,
@NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
- @NonNull BiometricScheduler scheduler,
+ @NonNull BiometricScheduler<IBiometricsFingerprint, AidlSession> scheduler,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller,
@@ -389,8 +389,8 @@
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
- final BiometricScheduler scheduler =
- new BiometricScheduler(TAG,
+ final BiometricScheduler<IBiometricsFingerprint, AidlSession> scheduler =
+ new BiometricScheduler<>(
BiometricScheduler.sensorTypeFromFingerprintProperties(sensorProps),
gestureAvailabilityDispatcher);
final HalResultController controller = new HalResultController(sensorProps.sensorId,
@@ -533,8 +533,8 @@
private void scheduleUpdateActiveUserWithoutHandler(int targetUserId, boolean force) {
final boolean hasEnrolled =
!getEnrolledFingerprints(mSensorProperties.sensorId, targetUserId).isEmpty();
- final FingerprintUpdateActiveUserClient client =
- new FingerprintUpdateActiveUserClient(mContext, mLazyDaemon, targetUserId,
+ final FingerprintUpdateActiveUserClientLegacy client =
+ new FingerprintUpdateActiveUserClientLegacy(mContext, mLazyDaemon, targetUserId,
mContext.getOpPackageName(), mSensorProperties.sensorId,
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 88dae6f..9232e11 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -140,9 +140,9 @@
private static class TestableBiometricScheduler extends BiometricScheduler {
@NonNull private Fingerprint21UdfpsMock mFingerprint21;
- TestableBiometricScheduler(@NonNull String tag, @NonNull Handler handler,
+ TestableBiometricScheduler(
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
- super(tag, BiometricScheduler.SENSOR_TYPE_FP_OTHER, gestureAvailabilityDispatcher);
+ super(BiometricScheduler.SENSOR_TYPE_FP_OTHER, gestureAvailabilityDispatcher);
}
void init(@NonNull Fingerprint21UdfpsMock fingerprint21) {
@@ -258,7 +258,7 @@
final Handler handler = new Handler(Looper.getMainLooper());
final TestableBiometricScheduler scheduler =
- new TestableBiometricScheduler(TAG, handler, gestureAvailabilityDispatcher);
+ new TestableBiometricScheduler(gestureAvailabilityDispatcher);
final MockHalResultController controller =
new MockHalResultController(sensorProps.sensorId, context, handler, scheduler);
return new Fingerprint21UdfpsMock(context, biometricStateCallback,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
index 5c5b992..59e64cd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.content.Context;
-import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.biometrics.fingerprint.ISession;
import android.os.Build;
import android.os.Environment;
import android.os.RemoteException;
@@ -39,8 +39,8 @@
/**
* Sets the HAL's current active user, and updates the framework's authenticatorId cache.
*/
-public class FingerprintUpdateActiveUserClient extends
- StartUserClient<IBiometricsFingerprint, AidlSession> {
+public class FingerprintUpdateActiveUserClient extends StartUserClient<ISession,
+ AidlSession> {
private static final String TAG = "FingerprintUpdateActiveUserClient";
private static final String FP_DATA_DIR = "fpdata";
@@ -52,19 +52,7 @@
private File mDirectory;
FingerprintUpdateActiveUserClient(@NonNull Context context,
- @NonNull Supplier<IBiometricsFingerprint> lazyDaemon, int userId,
- @NonNull String owner, int sensorId,
- @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
- @NonNull Supplier<Integer> currentUserId,
- boolean hasEnrolledBiometrics, @NonNull Map<Integer, Long> authenticatorIds,
- boolean forceUpdateAuthenticatorId) {
- this(context, lazyDaemon, userId, owner, sensorId, logger, biometricContext, currentUserId,
- hasEnrolledBiometrics, authenticatorIds, forceUpdateAuthenticatorId,
- (newUserId, newUser, halInterfaceVersion) -> {});
- }
-
- FingerprintUpdateActiveUserClient(@NonNull Context context,
- @NonNull Supplier<IBiometricsFingerprint> lazyDaemon, int userId,
+ @NonNull Supplier<ISession> lazyDaemon, int userId,
@NonNull String owner, int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull Supplier<Integer> currentUserId,
@@ -132,9 +120,10 @@
try {
final int targetId = getTargetUserId();
Slog.d(TAG, "Setting active user: " + targetId);
- getFreshDaemon().setActiveGroup(targetId, mDirectory.getAbsolutePath());
+ HidlToAidlSessionAdapter sessionAdapter = (HidlToAidlSessionAdapter) getFreshDaemon();
+ sessionAdapter.setActiveGroup(targetId, mDirectory.getAbsolutePath());
mAuthenticatorIds.put(targetId, mHasEnrolledBiometrics
- ? getFreshDaemon().getAuthenticatorId() : 0L);
+ ? sessionAdapter.getAuthenticatorIdForUpdateClient() : 0L);
mUserStartedCallback.onUserStarted(targetId, null, 0);
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClientLegacy.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClientLegacy.java
new file mode 100644
index 0000000..fc85402
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClientLegacy.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.fingerprint.hidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.os.Build;
+import android.os.Environment;
+import android.os.RemoteException;
+import android.os.SELinux;
+import android.util.Slog;
+
+import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
+import com.android.server.biometrics.sensors.HalClientMonitor;
+
+import java.io.File;
+import java.util.Map;
+import java.util.function.Supplier;
+
+/**
+ * TODO(b/304604965): Delete this class once Flags.DE_HIDL is ready for release.
+ */
+public class FingerprintUpdateActiveUserClientLegacy extends
+ HalClientMonitor<IBiometricsFingerprint> {
+ private static final String TAG = "FingerprintUpdateActiveUserClient";
+ private static final String FP_DATA_DIR = "fpdata";
+
+ private final Supplier<Integer> mCurrentUserId;
+ private final boolean mForceUpdateAuthenticatorId;
+ private final boolean mHasEnrolledBiometrics;
+ private final Map<Integer, Long> mAuthenticatorIds;
+ private File mDirectory;
+
+ FingerprintUpdateActiveUserClientLegacy(@NonNull Context context,
+ @NonNull Supplier<IBiometricsFingerprint> lazyDaemon, int userId,
+ @NonNull String owner, int sensorId,
+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
+ @NonNull Supplier<Integer> currentUserId,
+ boolean hasEnrolledBiometrics, @NonNull Map<Integer, Long> authenticatorIds,
+ boolean forceUpdateAuthenticatorId) {
+ super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
+ 0 /* cookie */, sensorId, logger, biometricContext);
+ mCurrentUserId = currentUserId;
+ mForceUpdateAuthenticatorId = forceUpdateAuthenticatorId;
+ mHasEnrolledBiometrics = hasEnrolledBiometrics;
+ mAuthenticatorIds = authenticatorIds;
+ }
+
+ @Override
+ public void start(@NonNull ClientMonitorCallback callback) {
+ super.start(callback);
+
+ if (mCurrentUserId.get() == getTargetUserId() && !mForceUpdateAuthenticatorId) {
+ Slog.d(TAG, "Already user: " + mCurrentUserId + ", returning");
+ callback.onClientFinished(this, true /* success */);
+ return;
+ }
+
+ int firstSdkInt = Build.VERSION.DEVICE_INITIAL_SDK_INT;
+ if (firstSdkInt < Build.VERSION_CODES.BASE) {
+ Slog.e(TAG, "First SDK version " + firstSdkInt + " is invalid; must be "
+ + "at least VERSION_CODES.BASE");
+ }
+ File baseDir;
+ if (firstSdkInt <= Build.VERSION_CODES.O_MR1) {
+ baseDir = Environment.getUserSystemDirectory(getTargetUserId());
+ } else {
+ baseDir = Environment.getDataVendorDeDirectory(getTargetUserId());
+ }
+
+ mDirectory = new File(baseDir, FP_DATA_DIR);
+ if (!mDirectory.exists()) {
+ if (!mDirectory.mkdir()) {
+ Slog.e(TAG, "Cannot make directory: " + mDirectory.getAbsolutePath());
+ callback.onClientFinished(this, false /* success */);
+ return;
+ }
+ // Calling mkdir() from this process will create a directory with our
+ // permissions (inherited from the containing dir). This command fixes
+ // the label.
+ if (!SELinux.restorecon(mDirectory)) {
+ Slog.e(TAG, "Restorecons failed. Directory will have wrong label.");
+ callback.onClientFinished(this, false /* success */);
+ return;
+ }
+ }
+
+ startHalOperation();
+ }
+
+ @Override
+ public void unableToStart() {
+ // Nothing to do here
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ final int targetId = getTargetUserId();
+ Slog.d(TAG, "Setting active user: " + targetId);
+ getFreshDaemon().setActiveGroup(targetId, mDirectory.getAbsolutePath());
+ mAuthenticatorIds.put(targetId, mHasEnrolledBiometrics
+ ? getFreshDaemon().getAuthenticatorId() : 0L);
+ mCallback.onClientFinished(this, true /* success */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to setActiveGroup: " + e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_UPDATE_ACTIVE_USER;
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java
index 0bb61415..abf48d1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.os.Handler;
@@ -39,7 +40,7 @@
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.StartUserClient;
import com.android.server.biometrics.sensors.StopUserClient;
-import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
+import com.android.server.biometrics.sensors.UserSwitchProvider;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import com.android.server.biometrics.sensors.fingerprint.aidl.AidlResponseHandler;
@@ -71,37 +72,33 @@
}
};
- public HidlToAidlSensorAdapter(@NonNull String tag, @NonNull FingerprintProvider provider,
- @NonNull Context context, @NonNull Handler handler,
+ public HidlToAidlSensorAdapter(@NonNull FingerprintProvider provider,
+ @NonNull Context context,
+ @NonNull Handler handler,
@NonNull SensorProps prop,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext,
boolean resetLockoutRequiresHardwareAuthToken,
@NonNull Runnable internalCleanupRunnable) {
- this(tag, provider, context, handler, prop, lockoutResetDispatcher,
- gestureAvailabilityDispatcher, biometricContext,
+ this(provider, context, handler, prop, lockoutResetDispatcher, biometricContext,
resetLockoutRequiresHardwareAuthToken, internalCleanupRunnable,
new AuthSessionCoordinator(), null /* daemon */,
null /* onEnrollSuccessCallback */);
}
@VisibleForTesting
- HidlToAidlSensorAdapter(@NonNull String tag, @NonNull FingerprintProvider provider,
+ HidlToAidlSensorAdapter(@NonNull FingerprintProvider provider,
@NonNull Context context, @NonNull Handler handler,
@NonNull SensorProps prop,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext,
boolean resetLockoutRequiresHardwareAuthToken,
@NonNull Runnable internalCleanupRunnable,
@NonNull AuthSessionCoordinator authSessionCoordinator,
@Nullable IBiometricsFingerprint daemon,
@Nullable AidlResponseHandler.AidlResponseHandlerCallback aidlResponseHandlerCallback) {
- super(tag, provider, context, handler, getFingerprintSensorPropertiesInternal(prop,
+ super(provider, context, handler, getFingerprintSensorPropertiesInternal(prop,
new ArrayList<>(), resetLockoutRequiresHardwareAuthToken),
- lockoutResetDispatcher,
- gestureAvailabilityDispatcher,
biometricContext, null /* session */);
mLockoutResetDispatcher = lockoutResetDispatcher;
mInternalCleanupRunnable = internalCleanupRunnable;
@@ -127,7 +124,7 @@
@Override
public void serviceDied(long cookie) {
- Slog.d(TAG, "HAL died.");
+ Slog.d(TAG, "Fingerprint HAL died.");
mSession = null;
mDaemon = null;
}
@@ -139,12 +136,12 @@
}
@Override
- public void init(GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
- LockoutResetDispatcher lockoutResetDispatcher) {
+ public void init(@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
setLazySession(this::getSession);
- setScheduler(new UserAwareBiometricScheduler(TAG,
+ setScheduler(new BiometricScheduler<ISession, AidlSession>(getHandler(),
BiometricScheduler.sensorTypeFromFingerprintProperties(getSensorProperties()),
- gestureAvailabilityDispatcher, () -> mCurrentUserId, getUserSwitchCallback()));
+ gestureAvailabilityDispatcher, () -> mCurrentUserId, getUserSwitchProvider()));
mLockoutTracker = new LockoutFrameworkImpl(getContext(),
userId -> mLockoutResetDispatcher.notifyLockoutResetCallbacks(
getSensorProperties().sensorId));
@@ -152,6 +149,7 @@
@Override
@Nullable
+ @VisibleForTesting
protected AidlSession getSessionForUser(int userId) {
if (mSession != null && mSession.getUserId() == userId) {
return mSession;
@@ -217,21 +215,18 @@
}
mDaemon.asBinder().linkToDeath(this, 0 /* flags */);
-
- Slog.d(TAG, "Fingerprint HAL ready");
-
scheduleLoadAuthenticatorIds();
mInternalCleanupRunnable.run();
return mDaemon;
}
- private UserAwareBiometricScheduler.UserSwitchCallback getUserSwitchCallback() {
- return new UserAwareBiometricScheduler.UserSwitchCallback() {
+ private UserSwitchProvider<ISession, AidlSession> getUserSwitchProvider() {
+ return new UserSwitchProvider<>() {
@NonNull
@Override
- public StopUserClient<?> getStopUserClient(int userId) {
- return new StopUserClient<IBiometricsFingerprint>(getContext(),
- HidlToAidlSensorAdapter.this::getIBiometricsFingerprint,
+ public StopUserClient<AidlSession> getStopUserClient(int userId) {
+ return new StopUserClient<>(getContext(),
+ HidlToAidlSensorAdapter.this::getSession,
null /* token */, userId, getSensorProperties().sensorId,
BiometricLogger.ofUnknown(getContext()), getBiometricContext(),
() -> {
@@ -258,7 +253,7 @@
@NonNull
@Override
- public StartUserClient<?, ?> getStartUserClient(int newUserId) {
+ public StartUserClient<ISession, AidlSession> getStartUserClient(int newUserId) {
return getFingerprintUpdateActiveUserClient(newUserId,
false /* forceUpdateAuthenticatorId */);
}
@@ -268,7 +263,7 @@
private FingerprintUpdateActiveUserClient getFingerprintUpdateActiveUserClient(int newUserId,
boolean forceUpdateAuthenticatorIds) {
return new FingerprintUpdateActiveUserClient(getContext(),
- this::getIBiometricsFingerprint, newUserId, TAG,
+ () -> getSession().getSession(), newUserId, TAG,
getSensorProperties().sensorId, BiometricLogger.ofUnknown(getContext()),
getBiometricContext(), () -> mCurrentUserId,
!FingerprintUtils.getInstance(getSensorProperties().sensorId)
@@ -290,7 +285,7 @@
}
@VisibleForTesting void handleUserChanged(int newUserId) {
- Slog.d(TAG, "User changed. Current user is " + newUserId);
+ Slog.d(TAG, "User changed. Current user for fingerprint sensor is " + newUserId);
mSession = null;
mCurrentUserId = newUserId;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapter.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapter.java
index 2fc00e1..b469752 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapter.java
@@ -209,6 +209,14 @@
return null;
}
+ public long getAuthenticatorIdForUpdateClient() throws RemoteException {
+ return mSession.get().getAuthenticatorId();
+ }
+
+ public void setActiveGroup(int userId, String absolutePath) throws RemoteException {
+ mSession.get().setActiveGroup(userId, absolutePath);
+ }
+
private void setCallback(AidlResponseHandler aidlResponseHandler) {
mHidlToAidlCallbackConverter = new HidlToAidlCallbackConverter(aidlResponseHandler);
try {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 8929900..f7480de 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -44,12 +44,18 @@
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.fingerprint.IFingerprint;
+import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.Fingerprint;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
import android.testing.TestableLooper;
@@ -60,6 +66,7 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.nano.BiometricSchedulerProto;
@@ -95,14 +102,39 @@
@Rule
public final TestableContext mContext = new TestableContext(
InstrumentationRegistry.getContext(), null);
- private BiometricScheduler mScheduler;
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
+ private BiometricScheduler<IFingerprint, ISession> mScheduler;
private IBinder mToken;
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
+ private boolean mShouldFailStopUser = false;
+ private final List<Integer> mStartedUsers = new ArrayList<>();
+ private final StartUserClient.UserStartedCallback<ISession> mUserStartedCallback =
+ (newUserId, newUser, halInterfaceVersion) -> {
+ mStartedUsers.add(newUserId);
+ mCurrentUserId = newUserId;
+ };
+ private int mUsersStoppedCount = 0;
+ private final StopUserClient.UserStoppedCallback mUserStoppedCallback =
+ () -> {
+ mUsersStoppedCount++;
+ mCurrentUserId = UserHandle.USER_NULL;
+ };
+ private boolean mStartOperationsFinish = true;
+ private int mStartUserClientCount = 0;
@Mock
private IBiometricService mBiometricService;
@Mock
private BiometricContext mBiometricContext;
@Mock
private AuthSessionCoordinator mAuthSessionCoordinator;
+ @Mock
+ private BiometricLogger mBiometricLogger;
+ @Mock
+ private ISession mSession;
+ @Mock
+ private IFingerprint mFingerprint;
@Before
public void setUp() {
@@ -111,9 +143,39 @@
when(mAuthSessionCoordinator.getLockoutStateFor(anyInt(), anyInt())).thenReturn(
BIOMETRIC_SUCCESS);
when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
- mScheduler = new BiometricScheduler(TAG, new Handler(TestableLooper.get(this).getLooper()),
- BiometricScheduler.SENSOR_TYPE_UNKNOWN, null /* gestureAvailabilityTracker */,
- mBiometricService, LOG_NUM_RECENT_OPERATIONS);
+ if (Flags.deHidl()) {
+ mScheduler = new BiometricScheduler<>(
+ new Handler(TestableLooper.get(this).getLooper()),
+ BiometricScheduler.SENSOR_TYPE_UNKNOWN,
+ null /* gestureAvailabilityDispatcher */,
+ mBiometricService,
+ LOG_NUM_RECENT_OPERATIONS,
+ () -> mCurrentUserId,
+ new UserSwitchProvider<IFingerprint, ISession>() {
+ @NonNull
+ @Override
+ public StopUserClient<ISession> getStopUserClient(int userId) {
+ return new TestStopUserClient(mContext, () -> mSession, mToken, userId,
+ TEST_SENSOR_ID, mBiometricLogger, mBiometricContext,
+ mUserStoppedCallback, () -> mShouldFailStopUser);
+ }
+
+ @NonNull
+ @Override
+ public StartUserClient<IFingerprint, ISession> getStartUserClient(
+ int newUserId) {
+ mStartUserClientCount++;
+ return new TestStartUserClient(mContext, () -> mFingerprint, mToken,
+ newUserId, TEST_SENSOR_ID, mBiometricLogger, mBiometricContext,
+ mUserStartedCallback, mStartOperationsFinish);
+ }
+ });
+ } else {
+ mScheduler = new BiometricScheduler<>(
+ new Handler(TestableLooper.get(this).getLooper()),
+ BiometricScheduler.SENSOR_TYPE_UNKNOWN, null /* gestureAvailabilityTracker */,
+ mBiometricService, LOG_NUM_RECENT_OPERATIONS);
+ }
}
@Test
@@ -479,6 +541,7 @@
final boolean isEnroll = client instanceof TestEnrollClient;
mScheduler.scheduleClientMonitor(client);
+ waitForIdle();
if (started) {
mScheduler.startPreparedClient(client.getCookie());
}
@@ -789,6 +852,172 @@
assertEquals(1, client1.getFingerprints().size());
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testScheduleOperation_whenNoUser() {
+ mCurrentUserId = UserHandle.USER_NULL;
+
+ final BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(0);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+ waitForIdle();
+
+ assertThat(mUsersStoppedCount).isEqualTo(0);
+ assertThat(mStartedUsers).containsExactly(0);
+ verify(nextClient).start(any());
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testScheduleOperation_whenNoUser_notStarted() {
+ mCurrentUserId = UserHandle.USER_NULL;
+ mStartOperationsFinish = false;
+
+ final BaseClientMonitor[] nextClients = new BaseClientMonitor[]{
+ mock(BaseClientMonitor.class),
+ mock(BaseClientMonitor.class),
+ mock(BaseClientMonitor.class)
+ };
+ for (BaseClientMonitor client : nextClients) {
+ when(client.getTargetUserId()).thenReturn(5);
+ mScheduler.scheduleClientMonitor(client);
+ waitForIdle();
+ }
+
+ assertThat(mUsersStoppedCount).isEqualTo(0);
+ assertThat(mStartedUsers).isEmpty();
+ assertThat(mStartUserClientCount).isEqualTo(1);
+ for (BaseClientMonitor client : nextClients) {
+ verify(client, never()).start(any());
+ }
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testScheduleOperation_whenNoUser_notStarted_andReset() {
+ mCurrentUserId = UserHandle.USER_NULL;
+ mStartOperationsFinish = false;
+
+ final BaseClientMonitor client = mock(BaseClientMonitor.class);
+
+ when(client.getTargetUserId()).thenReturn(5);
+
+ mScheduler.scheduleClientMonitor(client);
+ waitForIdle();
+
+ final TestStartUserClient startUserClient =
+ (TestStartUserClient) mScheduler.mCurrentOperation.getClientMonitor();
+ mScheduler.reset();
+
+ assertThat(mScheduler.mCurrentOperation).isNull();
+
+ final BiometricSchedulerOperation fakeOperation = new BiometricSchedulerOperation(
+ mock(BaseClientMonitor.class), new ClientMonitorCallback() {});
+ mScheduler.mCurrentOperation = fakeOperation;
+ startUserClient.mCallback.onClientFinished(startUserClient, true);
+
+ assertThat(fakeOperation).isSameInstanceAs(mScheduler.mCurrentOperation);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testScheduleOperation_whenSameUser() {
+ mCurrentUserId = 10;
+
+ BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(mCurrentUserId);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+
+ verify(nextClient).start(any());
+ assertThat(mUsersStoppedCount).isEqualTo(0);
+ assertThat(mStartedUsers).isEmpty();
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testScheduleOperation_whenDifferentUser() {
+ mCurrentUserId = 10;
+
+ final int nextUserId = 11;
+ BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(nextUserId);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ assertThat(mUsersStoppedCount).isEqualTo(1);
+
+ waitForIdle();
+ assertThat(mStartedUsers).containsExactly(nextUserId);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testStartUser_alwaysStartsNextOperation() {
+ mCurrentUserId = UserHandle.USER_NULL;
+
+ BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(10);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+
+ // finish first operation
+ mScheduler.getInternalCallback().onClientFinished(nextClient, true /* success */);
+ waitForIdle();
+
+ // schedule second operation but swap out the current operation
+ // before it runs so that it's not current when it's completion callback runs
+ nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(11);
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+ assertThat(mStartedUsers).containsExactly(10, 11).inOrder();
+ assertThat(mUsersStoppedCount).isEqualTo(1);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testStartUser_failsClearsStopUserClient() {
+ mCurrentUserId = UserHandle.USER_NULL;
+
+ // When a stop user client fails, check that mStopUserClient
+ // is set to null to prevent the scheduler from getting stuck.
+ BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(10);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+
+ // finish first operation
+ mScheduler.getInternalCallback().onClientFinished(nextClient, true /* success */);
+ waitForIdle();
+
+ // schedule second operation but swap out the current operation
+ // before it runs so that it's not current when it's completion callback runs
+ nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(11);
+ mShouldFailStopUser = true;
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ assertThat(mStartedUsers).containsExactly(10, 11).inOrder();
+ assertThat(mUsersStoppedCount).isEqualTo(0);
+ assertThat(mScheduler.getStopUserClient()).isEqualTo(null);
+ }
private BiometricSchedulerProto getDump(boolean clearSchedulerBuffer) throws Exception {
return BiometricSchedulerProto.parseFrom(mScheduler.dumpProtoState(clearSchedulerBuffer));
@@ -1069,4 +1298,82 @@
return mFingerprints;
}
}
+
+ private interface StopUserClientShouldFail {
+ boolean shouldFail();
+ }
+
+ private class TestStopUserClient extends StopUserClient<ISession> {
+ private StopUserClientShouldFail mShouldFailClient;
+ TestStopUserClient(@NonNull Context context,
+ @NonNull Supplier<ISession> lazyDaemon, @Nullable IBinder token, int userId,
+ int sensorId, @NonNull BiometricLogger logger,
+ @NonNull BiometricContext biometricContext,
+ @NonNull UserStoppedCallback callback, StopUserClientShouldFail shouldFail) {
+ super(context, lazyDaemon, token, userId, sensorId, logger, biometricContext, callback);
+ mShouldFailClient = shouldFail;
+ }
+
+ @Override
+ protected void startHalOperation() {
+
+ }
+
+ @Override
+ public void start(@NonNull ClientMonitorCallback callback) {
+ super.start(callback);
+ if (mShouldFailClient.shouldFail()) {
+ getCallback().onClientFinished(this, false /* success */);
+ // When the above fails, it means that the HAL has died, in this case we
+ // need to ensure the UserSwitchCallback correctly returns the NULL user handle.
+ mCurrentUserId = UserHandle.USER_NULL;
+ } else {
+ onUserStopped();
+ }
+ }
+
+ @Override
+ public void unableToStart() {
+
+ }
+ }
+
+ private static class TestStartUserClient extends StartUserClient<IFingerprint, ISession> {
+
+ @Mock
+ private ISession mSession;
+ private final boolean mShouldFinish;
+ ClientMonitorCallback mCallback;
+
+ TestStartUserClient(@NonNull Context context,
+ @NonNull Supplier<IFingerprint> lazyDaemon, @Nullable IBinder token, int userId,
+ int sensorId, @NonNull BiometricLogger logger,
+ @NonNull BiometricContext biometricContext,
+ @NonNull UserStartedCallback<ISession> callback, boolean shouldFinish) {
+ super(context, lazyDaemon, token, userId, sensorId, logger, biometricContext, callback);
+ mShouldFinish = shouldFinish;
+ }
+
+ @Override
+ protected void startHalOperation() {
+
+ }
+
+ @Override
+ public void start(@NonNull ClientMonitorCallback callback) {
+ super.start(callback);
+
+ mCallback = callback;
+ if (mShouldFinish) {
+ mUserStartedCallback.onUserStarted(
+ getTargetUserId(), mSession, 1 /* halInterfaceVersion */);
+ callback.onClientFinished(this, true /* success */);
+ }
+ }
+
+ @Override
+ public void unableToStart() {
+
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
index 8b1a291..772ec8b 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
@@ -36,8 +36,10 @@
import android.hardware.biometrics.face.ISession;
import android.hardware.biometrics.face.SensorProps;
import android.hardware.face.HidlFaceSensorConfig;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.UserManager;
+import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
@@ -88,14 +90,11 @@
@Mock
private BiometricStateCallback mBiometricStateCallback;
+ private final TestLooper mLooper = new TestLooper();
private SensorProps[] mSensorProps;
private LockoutResetDispatcher mLockoutResetDispatcher;
private FaceProvider mFaceProvider;
- private static void waitForIdle() {
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
- }
-
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
@@ -121,7 +120,8 @@
mFaceProvider = new FaceProvider(mContext, mBiometricStateCallback,
mSensorProps, TAG, mLockoutResetDispatcher, mBiometricContext,
- mDaemon, false /* resetLockoutRequiresChallenge */, false /* testHalEnabled */);
+ mDaemon, new Handler(mLooper.getLooper()),
+ false /* resetLockoutRequiresChallenge */, false /* testHalEnabled */);
}
@Test
@@ -156,6 +156,7 @@
mFaceProvider = new FaceProvider(mContext,
mBiometricStateCallback, hidlFaceSensorConfig, TAG,
mLockoutResetDispatcher, mBiometricContext, mDaemon,
+ new Handler(mLooper.getLooper()),
true /* resetLockoutRequiresChallenge */,
true /* testHalEnabled */);
@@ -210,4 +211,12 @@
assertEquals(0, scheduler.getCurrentPendingCount());
}
}
+
+ private void waitForIdle() {
+ if (Flags.deHidl()) {
+ mLooper.dispatchAll();
+ } else {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
index e7f7195..fe9cd43 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
@@ -31,6 +31,7 @@
import android.content.Context;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.common.CommonProps;
+import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.ISession;
import android.hardware.biometrics.face.SensorProps;
import android.hardware.face.FaceSensorPropertiesInternal;
@@ -40,6 +41,7 @@
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
@@ -49,6 +51,7 @@
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
+import com.android.server.biometrics.sensors.UserSwitchProvider;
import org.junit.Before;
import org.junit.Test;
@@ -74,6 +77,8 @@
@Mock
private UserAwareBiometricScheduler.UserSwitchCallback mUserSwitchCallback;
@Mock
+ private UserSwitchProvider<IFace, ISession> mUserSwitchProvider;
+ @Mock
private AidlResponseHandler.HardwareUnavailableCallback mHardwareUnavailableCallback;
@Mock
private LockoutResetDispatcher mLockoutResetDispatcher;
@@ -84,16 +89,16 @@
@Mock
private AuthSessionCoordinator mAuthSessionCoordinator;
@Mock
- FaceProvider mFaceProvider;
+ private FaceProvider mFaceProvider;
@Mock
- BaseClientMonitor mClientMonitor;
+ private BaseClientMonitor mClientMonitor;
@Mock
- AidlSession mCurrentSession;
+ private AidlSession mCurrentSession;
private final TestLooper mLooper = new TestLooper();
private final LockoutCache mLockoutCache = new LockoutCache();
- private UserAwareBiometricScheduler mScheduler;
+ private BiometricScheduler<IFace, ISession> mScheduler;
private AidlResponseHandler mHalCallback;
@Before
@@ -101,16 +106,26 @@
MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.BIOMETRIC_SERVICE)).thenReturn(mBiometricService);
-
when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
- mScheduler = new UserAwareBiometricScheduler(TAG,
- new Handler(mLooper.getLooper()),
- BiometricScheduler.SENSOR_TYPE_FACE,
- null /* gestureAvailabilityDispatcher */,
- mBiometricService,
- () -> USER_ID,
- mUserSwitchCallback);
+ if (Flags.deHidl()) {
+ mScheduler = new BiometricScheduler<>(
+ new Handler(mLooper.getLooper()),
+ BiometricScheduler.SENSOR_TYPE_FACE,
+ null /* gestureAvailabilityDispatcher */,
+ mBiometricService,
+ 2 /* recentOperationsLimit */,
+ () -> USER_ID,
+ mUserSwitchProvider);
+ } else {
+ mScheduler = new UserAwareBiometricScheduler<>(TAG,
+ new Handler(mLooper.getLooper()),
+ BiometricScheduler.SENSOR_TYPE_FACE,
+ null /* gestureAvailabilityDispatcher */,
+ mBiometricService,
+ () -> USER_ID,
+ mUserSwitchCallback);
+ }
mHalCallback = new AidlResponseHandler(mContext, mScheduler, SENSOR_ID, USER_ID,
mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator,
mHardwareUnavailableCallback);
@@ -146,18 +161,8 @@
@Test
public void onBinderDied_noErrorOnNullClient() {
mLooper.dispatchAll();
-
- final SensorProps sensorProps = new SensorProps();
- sensorProps.commonProps = new CommonProps();
- sensorProps.commonProps.sensorId = 1;
- final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
- sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
- sensorProps.commonProps.maxEnrollmentsPerUser, null /* componentInfo */,
- sensorProps.sensorType, sensorProps.supportsDetectInteraction,
- sensorProps.halControlsPreview, false /* resetLockoutRequiresChallenge */);
- final Sensor sensor = new Sensor("SensorTest", mFaceProvider, mContext,
- null /* handler */, internalProp, mLockoutResetDispatcher, mBiometricContext);
- sensor.init(mLockoutResetDispatcher, mFaceProvider);
+ final Sensor sensor = getSensor();
+ mScheduler = sensor.getScheduler();
mScheduler.reset();
assertNull(mScheduler.getCurrentClient());
@@ -175,18 +180,8 @@
when(mClientMonitor.getTargetUserId()).thenReturn(USER_ID);
when(mClientMonitor.isInterruptable()).thenReturn(false);
- final SensorProps sensorProps = new SensorProps();
- sensorProps.commonProps = new CommonProps();
- sensorProps.commonProps.sensorId = 1;
- final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
- sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
- sensorProps.commonProps.maxEnrollmentsPerUser, null /* componentInfo */,
- sensorProps.sensorType, sensorProps.supportsDetectInteraction,
- sensorProps.halControlsPreview, false /* resetLockoutRequiresChallenge */);
- final Sensor sensor = new Sensor("SensorTest", mFaceProvider, mContext, null,
- internalProp, mLockoutResetDispatcher, mBiometricContext, mCurrentSession);
- sensor.init(mLockoutResetDispatcher, mFaceProvider);
- mScheduler = (UserAwareBiometricScheduler) sensor.getScheduler();
+ final Sensor sensor = getSensor();
+ mScheduler = sensor.getScheduler();
sensor.mCurrentSession = new AidlSession(0, mock(ISession.class),
USER_ID, mHalCallback);
@@ -206,4 +201,20 @@
verify(mLockoutResetDispatcher).notifyLockoutResetCallbacks(eq(SENSOR_ID));
verify(mAuthSessionCoordinator).resetLockoutFor(eq(USER_ID), anyInt(), anyLong());
}
+
+ private Sensor getSensor() {
+ final SensorProps sensorProps = new SensorProps();
+ sensorProps.commonProps = new CommonProps();
+ sensorProps.commonProps.sensorId = 1;
+ final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
+ sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
+ sensorProps.commonProps.maxEnrollmentsPerUser, null /* componentInfo */,
+ sensorProps.sensorType, sensorProps.supportsDetectInteraction,
+ sensorProps.halControlsPreview, false /* resetLockoutRequiresChallenge */);
+ final Sensor sensor = new Sensor(mFaceProvider, mContext,
+ null /* handler */, internalProp, mBiometricContext);
+ sensor.init(mLockoutResetDispatcher, mFaceProvider);
+
+ return sensor;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java
index 4e43332..940fe69 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java
@@ -45,7 +45,6 @@
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
-import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -88,9 +87,9 @@
@Mock
private IBiometricsFace mDaemon;
@Mock
- AidlResponseHandler.AidlResponseHandlerCallback mAidlResponseHandlerCallback;
+ private AidlResponseHandler.AidlResponseHandlerCallback mAidlResponseHandlerCallback;
@Mock
- BiometricUtils<Face> mBiometricUtils;
+ private BiometricUtils<Face> mBiometricUtils;
private final TestLooper mLooper = new TestLooper();
private HidlToAidlSensorAdapter mHidlToAidlSensorAdapter;
@@ -118,20 +117,14 @@
mContext.getOrCreateTestableResources();
final String config = String.format("%d:8:15", SENSOR_ID);
- final BiometricScheduler scheduler = new BiometricScheduler(TAG,
- new Handler(mLooper.getLooper()),
- BiometricScheduler.SENSOR_TYPE_FACE,
- null /* gestureAvailabilityTracker */,
- mBiometricService, 10 /* recentOperationsLimit */);
final HidlFaceSensorConfig faceSensorConfig = new HidlFaceSensorConfig();
faceSensorConfig.parse(config, mContext);
- mHidlToAidlSensorAdapter = new HidlToAidlSensorAdapter(TAG, mFaceProvider,
+ mHidlToAidlSensorAdapter = new HidlToAidlSensorAdapter(mFaceProvider,
mContext, new Handler(mLooper.getLooper()), faceSensorConfig,
mLockoutResetDispatcherForSensor, mBiometricContext,
false /* resetLockoutRequiresChallenge */, mInternalCleanupAndGetFeatureRunnable,
mAuthSessionCoordinator, mDaemon, mAidlResponseHandlerCallback);
mHidlToAidlSensorAdapter.init(mLockoutResetDispatcherForSensor, mFaceProvider);
- mHidlToAidlSensorAdapter.setScheduler(scheduler);
mHidlToAidlSensorAdapter.handleUserChanged(USER_ID);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index bf5986c..258be57 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -38,8 +38,10 @@
import android.hardware.biometrics.fingerprint.SensorLocation;
import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.fingerprint.HidlFingerprintSensorConfig;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.UserManager;
+import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
@@ -92,14 +94,12 @@
@Mock
private BiometricContext mBiometricContext;
+ private final TestLooper mLooper = new TestLooper();
+
private SensorProps[] mSensorProps;
private LockoutResetDispatcher mLockoutResetDispatcher;
private FingerprintProvider mFingerprintProvider;
- private static void waitForIdle() {
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
- }
-
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
@@ -126,7 +126,8 @@
mFingerprintProvider = new FingerprintProvider(mContext,
mBiometricStateCallback, mAuthenticationStateListeners, mSensorProps, TAG,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext,
- mDaemon, false /* resetLockoutRequiresHardwareAuthToken */,
+ mDaemon, new Handler(mLooper.getLooper()),
+ false /* resetLockoutRequiresHardwareAuthToken */,
true /* testHalEnabled */);
}
@@ -159,6 +160,7 @@
mBiometricStateCallback, mAuthenticationStateListeners,
hidlFingerprintSensorConfigs, TAG, mLockoutResetDispatcher,
mGestureAvailabilityDispatcher, mBiometricContext, mDaemon,
+ new Handler(mLooper.getLooper()),
false /* resetLockoutRequiresHardwareAuthToken */,
true /* testHalEnabled */);
@@ -215,4 +217,12 @@
assertEquals(0, scheduler.getCurrentPendingCount());
}
}
+
+ private void waitForIdle() {
+ if (Flags.deHidl()) {
+ mLooper.dispatchAll();
+ } else {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
index 126a05e..b4c2ee8 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
@@ -32,14 +32,17 @@
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.common.CommonProps;
import android.hardware.biometrics.face.SensorProps;
+import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
@@ -49,6 +52,7 @@
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
+import com.android.server.biometrics.sensors.UserSwitchProvider;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import org.junit.Before;
@@ -75,6 +79,8 @@
@Mock
private UserAwareBiometricScheduler.UserSwitchCallback mUserSwitchCallback;
@Mock
+ private UserSwitchProvider<IFingerprint, ISession> mUserSwitchProvider;
+ @Mock
private AidlResponseHandler.HardwareUnavailableCallback mHardwareUnavailableCallback;
@Mock
private LockoutResetDispatcher mLockoutResetDispatcher;
@@ -92,11 +98,13 @@
private AidlSession mCurrentSession;
@Mock
private BaseClientMonitor mClientMonitor;
+ @Mock
+ private HandlerThread mThread;
private final TestLooper mLooper = new TestLooper();
private final LockoutCache mLockoutCache = new LockoutCache();
- private BiometricScheduler mScheduler;
+ private BiometricScheduler<IFingerprint, ISession> mScheduler;
private AidlResponseHandler mHalCallback;
@Before
@@ -105,14 +113,26 @@
when(mContext.getSystemService(Context.BIOMETRIC_SERVICE)).thenReturn(mBiometricService);
when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
+ when(mThread.getLooper()).thenReturn(mLooper.getLooper());
- mScheduler = new UserAwareBiometricScheduler(TAG,
- new Handler(mLooper.getLooper()),
- BiometricScheduler.SENSOR_TYPE_FP_OTHER,
- null /* gestureAvailabilityDispatcher */,
- mBiometricService,
- () -> USER_ID,
- mUserSwitchCallback);
+ if (Flags.deHidl()) {
+ mScheduler = new BiometricScheduler<>(
+ new Handler(mLooper.getLooper()),
+ BiometricScheduler.SENSOR_TYPE_FP_OTHER,
+ null /* gestureAvailabilityDispatcher */,
+ mBiometricService,
+ 2 /* recentOperationsLimit */,
+ () -> USER_ID,
+ mUserSwitchProvider);
+ } else {
+ mScheduler = new UserAwareBiometricScheduler<>(TAG,
+ new Handler(mLooper.getLooper()),
+ BiometricScheduler.SENSOR_TYPE_FP_OTHER,
+ null /* gestureAvailabilityDispatcher */,
+ mBiometricService,
+ () -> USER_ID,
+ mUserSwitchCallback);
+ }
mHalCallback = new AidlResponseHandler(mContext, mScheduler, SENSOR_ID, USER_ID,
mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator,
mHardwareUnavailableCallback);
@@ -153,18 +173,7 @@
when(mClientMonitor.getTargetUserId()).thenReturn(USER_ID);
when(mClientMonitor.isInterruptable()).thenReturn(false);
- final SensorProps sensorProps = new SensorProps();
- sensorProps.commonProps = new CommonProps();
- sensorProps.commonProps.sensorId = 1;
- final FingerprintSensorPropertiesInternal internalProp = new
- FingerprintSensorPropertiesInternal(
- sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
- sensorProps.commonProps.maxEnrollmentsPerUser, null,
- sensorProps.sensorType, false /* resetLockoutRequiresHardwareAuthToken */);
- final Sensor sensor = new Sensor("SensorTest", mFingerprintProvider, mContext,
- null /* handler */, internalProp, mLockoutResetDispatcher,
- mGestureAvailabilityDispatcher, mBiometricContext, mCurrentSession);
- sensor.init(mGestureAvailabilityDispatcher, mLockoutResetDispatcher);
+ final Sensor sensor = getSensor();
mScheduler = sensor.getScheduler();
sensor.mCurrentSession = new AidlSession(0, mock(ISession.class),
USER_ID, mHalCallback);
@@ -185,4 +194,21 @@
verify(mLockoutResetDispatcher).notifyLockoutResetCallbacks(eq(SENSOR_ID));
verify(mAuthSessionCoordinator).resetLockoutFor(eq(USER_ID), anyInt(), anyLong());
}
+
+ private Sensor getSensor() {
+ final SensorProps sensorProps = new SensorProps();
+ sensorProps.commonProps = new CommonProps();
+ sensorProps.commonProps.sensorId = 1;
+ final FingerprintSensorPropertiesInternal internalProp = new
+ FingerprintSensorPropertiesInternal(
+ sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
+ sensorProps.commonProps.maxEnrollmentsPerUser, null,
+ sensorProps.sensorType, false /* resetLockoutRequiresHardwareAuthToken */);
+ final Sensor sensor = new Sensor(mFingerprintProvider, mContext,
+ null /* handler */, internalProp,
+ mBiometricContext, mCurrentSession);
+ sensor.init(mGestureAvailabilityDispatcher, mLockoutResetDispatcher);
+
+ return sensor;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java
index 59c94dc..01175e8 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java
@@ -36,12 +36,12 @@
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.HidlFingerprintSensorConfig;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext;
-import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
@@ -49,17 +49,11 @@
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationStateListeners;
-import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricUtils;
-import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
-import com.android.server.biometrics.sensors.StartUserClient;
-import com.android.server.biometrics.sensors.StopUserClient;
-import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import com.android.server.biometrics.sensors.fingerprint.aidl.AidlResponseHandler;
-import com.android.server.biometrics.sensors.fingerprint.aidl.AidlSession;
import com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintEnrollClient;
import com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintProvider;
import com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintResetLockoutClient;
@@ -112,60 +106,18 @@
private BiometricUtils<Fingerprint> mBiometricUtils;
@Mock
private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
+ private HandlerThread mThread;
private final TestLooper mLooper = new TestLooper();
private HidlToAidlSensorAdapter mHidlToAidlSensorAdapter;
private final TestableContext mContext = new TestableContext(
ApplicationProvider.getApplicationContext());
- private final UserAwareBiometricScheduler.UserSwitchCallback mUserSwitchCallback =
- new UserAwareBiometricScheduler.UserSwitchCallback() {
- @NonNull
- @Override
- public StopUserClient<?> getStopUserClient(int userId) {
- return new StopUserClient<IBiometricsFingerprint>(mContext,
- mHidlToAidlSensorAdapter::getIBiometricsFingerprint, null, USER_ID,
- SENSOR_ID, mLogger, mBiometricContext, () -> {}) {
- @Override
- protected void startHalOperation() {
- getCallback().onClientFinished(this, true /* success */);
- }
-
- @Override
- public void unableToStart() {}
- };
- }
-
- @NonNull
- @Override
- public StartUserClient<?, ?> getStartUserClient(int newUserId) {
- return new StartUserClient<IBiometricsFingerprint, AidlSession>(mContext,
- mHidlToAidlSensorAdapter::getIBiometricsFingerprint, null,
- USER_ID, SENSOR_ID,
- mLogger, mBiometricContext,
- (newUserId1, newUser, halInterfaceVersion) ->
- mHidlToAidlSensorAdapter.handleUserChanged(newUserId1)) {
- @Override
- public void start(@NonNull ClientMonitorCallback callback) {
- super.start(callback);
- startHalOperation();
- }
-
- @Override
- protected void startHalOperation() {
- mUserStartedCallback.onUserStarted(USER_ID, null, 0);
- getCallback().onClientFinished(this, true /* success */);
- }
-
- @Override
- public void unableToStart() {}
- };
- }
- };;
-
@Before
public void setUp() throws RemoteException {
when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
+ when(mThread.getLooper()).thenReturn(mLooper.getLooper());
doAnswer((answer) -> {
mHidlToAidlSensorAdapter.getLazySession().get().getHalSessionCallback()
.onEnrollmentProgress(1 /* enrollmentId */, 0 /* remaining */);
@@ -176,26 +128,18 @@
mContext.getOrCreateTestableResources();
final String config = String.format("%d:2:15", SENSOR_ID);
- final UserAwareBiometricScheduler scheduler = new UserAwareBiometricScheduler(TAG,
- new Handler(mLooper.getLooper()),
- BiometricScheduler.SENSOR_TYPE_FP_OTHER,
- null /* gestureAvailabilityDispatcher */,
- mBiometricService,
- () -> USER_ID,
- mUserSwitchCallback);
final HidlFingerprintSensorConfig fingerprintSensorConfig =
new HidlFingerprintSensorConfig();
fingerprintSensorConfig.parse(config, mContext);
- mHidlToAidlSensorAdapter = new HidlToAidlSensorAdapter(TAG,
+ mHidlToAidlSensorAdapter = new HidlToAidlSensorAdapter(
mFingerprintProvider, mContext, new Handler(mLooper.getLooper()),
fingerprintSensorConfig, mLockoutResetDispatcherForSensor,
- mGestureAvailabilityDispatcher, mBiometricContext,
- false /* resetLockoutRequiresHardwareAuthToken */,
+ mBiometricContext, false /* resetLockoutRequiresHardwareAuthToken */,
mInternalCleanupRunnable, mAuthSessionCoordinator, mDaemon,
mAidlResponseHandlerCallback);
mHidlToAidlSensorAdapter.init(mGestureAvailabilityDispatcher,
mLockoutResetDispatcherForSensor);
- mHidlToAidlSensorAdapter.setScheduler(scheduler);
+
mHidlToAidlSensorAdapter.handleUserChanged(USER_ID);
}