diff options
12 files changed, 150 insertions, 24 deletions
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 adda10eb109f..61266071f788 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java @@ -22,6 +22,7 @@ import android.annotation.Nullable;  import android.content.Context;  import android.hardware.biometrics.BiometricConstants;  import android.hardware.biometrics.IBiometricService; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;  import android.os.Handler;  import android.os.IBinder;  import android.os.Looper; @@ -48,8 +49,11 @@ import java.util.Locale;  /**   * A scheduler for biometric HAL operations. Maintains a queue of {@link BaseClientMonitor} - * operations, without caring about its implementation details. Operations may perform one or more + * operations, without caring about its implementation details. Operations may perform zero or more   * interactions with the HAL before finishing. + * + * We currently assume (and require) that each biometric sensor have its own instance of a + * {@link BiometricScheduler}. See {@link CoexCoordinator}.   */  public class BiometricScheduler { @@ -58,6 +62,55 @@ public class BiometricScheduler {      protected static final int LOG_NUM_RECENT_OPERATIONS = 50;      /** +     * Unknown sensor type. This should never be used, and is a sign that something is wrong during +     * initialization. +     */ +    public static final int SENSOR_TYPE_UNKNOWN = 0; + +    /** +     * Face authentication. +     */ +    public static final int SENSOR_TYPE_FACE = 1; + +    /** +     * Any UDFPS type. See {@link FingerprintSensorPropertiesInternal#isAnyUdfpsType()}. +     */ +    public static final int SENSOR_TYPE_UDFPS = 2; + +    /** +     * Any other fingerprint sensor. We can add additional definitions in the future when necessary. +     */ +    public static final int SENSOR_TYPE_FP_OTHER = 3; + +    @IntDef({SENSOR_TYPE_UNKNOWN, SENSOR_TYPE_FACE, SENSOR_TYPE_UDFPS, SENSOR_TYPE_FP_OTHER}) +    @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"; +        } +    } + +    /**       * Contains all the necessary information for a HAL operation.       */      @VisibleForTesting @@ -207,6 +260,7 @@ public class BiometricScheduler {      }      @NonNull protected final String mBiometricTag; +    private final @SensorType int mSensorType;      @Nullable private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;      @NonNull private final IBiometricService mBiometricService;      @NonNull protected final Handler mHandler = new Handler(Looper.getMainLooper()); @@ -218,6 +272,7 @@ public class BiometricScheduler {      private int mTotalOperationsHandled;      private final int mRecentOperationsLimit;      @NonNull private final List<Integer> mRecentOperations; +    @NonNull private final CoexCoordinator mCoexCoordinator;      // Internal callback, notified when an operation is complete. Notifies the requester      // that the operation is complete, before performing internal scheduler work (such as @@ -226,6 +281,12 @@ public class BiometricScheduler {          @Override          public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {              Slog.d(getTag(), "[Started] " + clientMonitor); + +            if (clientMonitor instanceof AuthenticationClient) { +                mCoexCoordinator.addAuthenticationClient(mSensorType, +                        (AuthenticationClient<?>) clientMonitor); +            } +              if (mCurrentOperation.mClientCallback != null) {                  mCurrentOperation.mClientCallback.onClientStarted(clientMonitor);              } @@ -248,6 +309,11 @@ public class BiometricScheduler {                  }                  Slog.d(getTag(), "[Finishing] " + clientMonitor + ", success: " + success); +                if (clientMonitor instanceof AuthenticationClient) { +                    mCoexCoordinator.removeAuthenticationClient(mSensorType, +                            (AuthenticationClient<?>) clientMonitor); +                } +                  mCurrentOperation.mState = Operation.STATE_FINISHED;                  if (mCurrentOperation.mClientCallback != null) { @@ -271,10 +337,12 @@ public class BiometricScheduler {      }      @VisibleForTesting -    BiometricScheduler(@NonNull String tag, +    BiometricScheduler(@NonNull String tag, @SensorType int sensorType,              @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher, -            @NonNull IBiometricService biometricService, int recentOperationsLimit) { +            @NonNull IBiometricService biometricService, int recentOperationsLimit, +            @NonNull CoexCoordinator coexCoordinator) {          mBiometricTag = tag; +        mSensorType = sensorType;          mInternalCallback = new InternalCallback();          mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher;          mPendingOperations = new ArrayDeque<>(); @@ -282,6 +350,7 @@ public class BiometricScheduler {          mCrashStates = new ArrayDeque<>();          mRecentOperationsLimit = recentOperationsLimit;          mRecentOperations = new ArrayList<>(); +        mCoexCoordinator = coexCoordinator;      }      /** @@ -290,10 +359,11 @@ public class BiometricScheduler {       * @param gestureAvailabilityDispatcher may be null if the sensor does not support gestures       *                                      (such as fingerprint swipe).       */ -    public BiometricScheduler(@NonNull String tag, +    public BiometricScheduler(@NonNull String tag, @SensorType int sensorType,              @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { -        this(tag, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface( -                ServiceManager.getService(Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS); +        this(tag, sensorType, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface( +                ServiceManager.getService(Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS, +                CoexCoordinator.getInstance());      }      /** @@ -645,6 +715,7 @@ public class BiometricScheduler {      public void dump(PrintWriter pw) {          pw.println("Dump of BiometricScheduler " + getTag()); +        pw.println("Type: " + mSensorType);          pw.println("Current operation: " + mCurrentOperation);          pw.println("Pending operations: " + mPendingOperations.size());          for (Operation operation : mPendingOperations) { diff --git a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java index cccb6e2d3c90..08bf2e020f75 100644 --- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java +++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java @@ -16,7 +16,13 @@  package com.android.server.biometrics.sensors; +import static com.android.server.biometrics.sensors.BiometricScheduler.sensorTypeToString; +  import android.annotation.NonNull; +import android.util.Slog; + +import java.util.HashMap; +import java.util.Map;  /**   * Singleton that contains the core logic for determining if haptics and authentication callbacks @@ -27,6 +33,7 @@ import android.annotation.NonNull;  public class CoexCoordinator {      private static final String TAG = "BiometricCoexCoordinator"; +    private static final boolean DEBUG = true;      /**       * Callback interface notifying the owner of "results" from the CoexCoordinator's business @@ -47,10 +54,6 @@ public class CoexCoordinator {      private static CoexCoordinator sInstance; -    private CoexCoordinator() { -        // Singleton -    } -      @NonNull      static CoexCoordinator getInstance() {          if (sInstance == null) { @@ -59,6 +62,43 @@ public class CoexCoordinator {          return sInstance;      } +    // SensorType to AuthenticationClient map +    private final Map<Integer, AuthenticationClient<?>> mClientMap; + +    private CoexCoordinator() { +        // Singleton +        mClientMap = new HashMap<>(); +    } + +    public void addAuthenticationClient(@BiometricScheduler.SensorType int sensorType, +            @NonNull AuthenticationClient<?> client) { +        if (DEBUG) { +            Slog.d(TAG, "addAuthenticationClient(" + sensorTypeToString(sensorType) + ")" +                    + ", client: " + client); +        } + +        if (mClientMap.containsKey(sensorType)) { +            Slog.w(TAG, "Overwriting existing client: " + mClientMap.get(sensorType) +                    + " with new client: " + client); +        } + +        mClientMap.put(sensorType, client); +    } + +    public void removeAuthenticationClient(@BiometricScheduler.SensorType int sensorType, +            @NonNull AuthenticationClient<?> client) { +        if (DEBUG) { +            Slog.d(TAG, "removeAuthenticationClient(" + sensorTypeToString(sensorType) + ")" +                    + ", client: " + client); +        } + +        if (!mClientMap.containsKey(sensorType)) { +            Slog.e(TAG, "sensorType: " + sensorType + " does not exist in map. Client: " + client); +            return; +        } +        mClientMap.remove(sensorType); +    } +      public void onAuthenticationSucceeded(@NonNull AuthenticationClient<?> client,              @NonNull Callback callback) {          if (client.isBiometricPrompt()) { 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 e6e293eb9b4c..b056bf897b5c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java +++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java @@ -83,24 +83,26 @@ public class UserAwareBiometricScheduler extends BiometricScheduler {      }      @VisibleForTesting -    UserAwareBiometricScheduler(@NonNull String tag, +    UserAwareBiometricScheduler(@NonNull String tag, @SensorType int sensorType,              @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,              @NonNull IBiometricService biometricService,              @NonNull CurrentUserRetriever currentUserRetriever, -            @NonNull UserSwitchCallback userSwitchCallback) { -        super(tag, gestureAvailabilityDispatcher, biometricService, LOG_NUM_RECENT_OPERATIONS); +            @NonNull UserSwitchCallback userSwitchCallback, +            @NonNull CoexCoordinator coexCoordinator) { +        super(tag, sensorType, gestureAvailabilityDispatcher, biometricService, +                LOG_NUM_RECENT_OPERATIONS, coexCoordinator);          mCurrentUserRetriever = currentUserRetriever;          mUserSwitchCallback = userSwitchCallback;      } -    public UserAwareBiometricScheduler(@NonNull String tag, +    public UserAwareBiometricScheduler(@NonNull String tag, @SensorType int sensorType,              @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,              @NonNull CurrentUserRetriever currentUserRetriever,              @NonNull UserSwitchCallback userSwitchCallback) { -        this(tag, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface( +        this(tag, sensorType, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface(                  ServiceManager.getService(Context.BIOMETRIC_SERVICE)), currentUserRetriever, -                userSwitchCallback); +                userSwitchCallback, CoexCoordinator.getInstance());      }      @Override 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 2f71f44b6bef..4abd402a4da8 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 @@ -494,7 +494,8 @@ public class Sensor {          mToken = new Binder();          mHandler = handler;          mSensorProperties = sensorProperties; -        mScheduler = new UserAwareBiometricScheduler(tag, null /* gestureAvailabilityDispatcher */, +        mScheduler = new UserAwareBiometricScheduler(tag, BiometricScheduler.SENSOR_TYPE_FACE, +                null /* gestureAvailabilityDispatcher */,                  () -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL,                  new UserAwareBiometricScheduler.UserSwitchCallback() {                      @NonNull 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 26c5bca7f726..e95273ae6a41 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 @@ -355,7 +355,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {      public Face10(@NonNull Context context, @NonNull FaceSensorPropertiesInternal sensorProps,              @NonNull LockoutResetDispatcher lockoutResetDispatcher) {          this(context, sensorProps, lockoutResetDispatcher, -                new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */)); +                new BiometricScheduler(TAG, BiometricScheduler.SENSOR_TYPE_FACE, +                        null /* gestureAvailabilityTracker */));      }      @Override 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 b3b818fd6d3d..59e4b582ca84 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 @@ -449,7 +449,9 @@ class Sensor {          mHandler = handler;          mSensorProperties = sensorProperties;          mLockoutCache = new LockoutCache(); -        mScheduler = new UserAwareBiometricScheduler(tag, gestureAvailabilityDispatcher, +        mScheduler = new UserAwareBiometricScheduler(tag, +                BiometricScheduler.sensorTypeFromFingerprintProperties(mSensorProperties), +                gestureAvailabilityDispatcher,                  () -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL,                  new UserAwareBiometricScheduler.UserSwitchCallback() {                      @NonNull 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 7daea88f0f22..a6385a541b03 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 @@ -352,7 +352,9 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider              @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {          final Handler handler = new Handler(Looper.getMainLooper());          final BiometricScheduler scheduler = -                new BiometricScheduler(TAG, gestureAvailabilityDispatcher); +                new BiometricScheduler(TAG, +                        BiometricScheduler.sensorTypeFromFingerprintProperties(sensorProps), +                        gestureAvailabilityDispatcher);          final HalResultController controller = new HalResultController(sensorProps.sensorId,                  context, handler,                  scheduler); 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 d1020a6ff068..312c52c4a844 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 @@ -138,7 +138,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage          TestableBiometricScheduler(@NonNull String tag,                  @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { -            super(tag, gestureAvailabilityDispatcher); +            super(tag, BiometricScheduler.SENSOR_TYPE_FP_OTHER, gestureAvailabilityDispatcher);              mInternalCallback = new TestableInternalCallback();          } 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 109fb22520c8..a8bf0c751e87 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 @@ -75,8 +75,9 @@ public class BiometricSchedulerTest {      public void setUp() {          MockitoAnnotations.initMocks(this);          mToken = new Binder(); -        mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */, -                mBiometricService, LOG_NUM_RECENT_OPERATIONS); +        mScheduler = new BiometricScheduler(TAG, BiometricScheduler.SENSOR_TYPE_UNKNOWN, +                null /* gestureAvailabilityTracker */, mBiometricService, LOG_NUM_RECENT_OPERATIONS, +                CoexCoordinator.getInstance());      }      @Test diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java index 3a9e629b6ed6..7fccd49db04b 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java @@ -74,6 +74,7 @@ public class UserAwareBiometricSchedulerTest {          mUserStoppedCallback = new TestUserStoppedCallback();          mScheduler = new UserAwareBiometricScheduler(TAG, +                BiometricScheduler.SENSOR_TYPE_UNKNOWN,                  null /* gestureAvailabilityDispatcher */,                  mBiometricService,                  () -> mCurrentUserId, @@ -92,7 +93,8 @@ public class UserAwareBiometricSchedulerTest {                          return new TestStartUserClient(mContext, Object::new, mToken, newUserId,                                  TEST_SENSOR_ID, mUserStartedCallback, mStartOperationsFinish);                      } -                }); +                }, +                CoexCoordinator.getInstance());      }      @Test 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 b8fbe34a7dcb..a13dff21439d 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 @@ -32,6 +32,7 @@ import android.platform.test.annotations.Presubmit;  import androidx.test.filters.SmallTest; +import com.android.server.biometrics.sensors.BiometricScheduler;  import com.android.server.biometrics.sensors.LockoutCache;  import com.android.server.biometrics.sensors.LockoutResetDispatcher;  import com.android.server.biometrics.sensors.LockoutTracker; @@ -78,6 +79,7 @@ public class SensorTest {          when(mContext.getSystemService(Context.BIOMETRIC_SERVICE)).thenReturn(mBiometricService);          mScheduler = new UserAwareBiometricScheduler(TAG, +                BiometricScheduler.SENSOR_TYPE_FACE,                  null /* gestureAvailabilityDispatcher */,                  () -> USER_ID,                  mUserSwitchCallback); 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 5dfc24889815..0d520ca9a4e4 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,6 +32,7 @@ import android.platform.test.annotations.Presubmit;  import androidx.test.filters.SmallTest; +import com.android.server.biometrics.sensors.BiometricScheduler;  import com.android.server.biometrics.sensors.LockoutCache;  import com.android.server.biometrics.sensors.LockoutResetDispatcher;  import com.android.server.biometrics.sensors.LockoutTracker; @@ -78,6 +79,7 @@ public class SensorTest {          when(mContext.getSystemService(Context.BIOMETRIC_SERVICE)).thenReturn(mBiometricService);          mScheduler = new UserAwareBiometricScheduler(TAG, +                BiometricScheduler.SENSOR_TYPE_FP_OTHER,                  null /* gestureAvailabilityDispatcher */,                  () -> USER_ID,                  mUserSwitchCallback);  |