Loading services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java +19 −7 Original line number Diff line number Diff line Loading @@ -563,14 +563,26 @@ public class BiometricScheduler { final boolean isAuthenticating = mCurrentOperation.mClientMonitor instanceof AuthenticationConsumer; final boolean tokenMatches = mCurrentOperation.mClientMonitor.getToken() == token; if (!isAuthenticating || !tokenMatches) { Slog.w(getTag(), "Not cancelling authentication" + ", current operation : " + mCurrentOperation + ", tokenMatches: " + tokenMatches); return; } if (isAuthenticating && tokenMatches) { Slog.d(getTag(), "Cancelling authentication: " + mCurrentOperation); cancelInternal(mCurrentOperation); } else if (!isAuthenticating) { // Look through the current queue for all authentication clients for the specified // token, and mark them as STATE_WAITING_IN_QUEUE_CANCELING. Note that we're marking // all of them, instead of just the first one, since the API surface currently doesn't // allow us to distinguish between multiple authentication requests from the same // process. However, this generally does not happen anyway, and would be a class of // bugs on its own. for (Operation operation : mPendingOperations) { if (operation.mClientMonitor instanceof AuthenticationConsumer && operation.mClientMonitor.getToken() == token) { Slog.d(getTag(), "Marking " + operation + " as STATE_WAITING_IN_QUEUE_CANCELING"); operation.mState = Operation.STATE_WAITING_IN_QUEUE_CANCELING; } } } } /** Loading services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java +57 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.IBiometricService; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import androidx.annotation.NonNull; Loading Loading @@ -267,6 +268,39 @@ public class BiometricSchedulerTest { assertEquals(0, bsp.recentOperations.length); } @Test public void testCancelPendingAuth() throws RemoteException { final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class); final TestClientMonitor client1 = new TestClientMonitor(mContext, mToken, lazyDaemon); final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon, mToken, callback); // Add a non-cancellable client, then add the auth client mScheduler.scheduleClientMonitor(client1); mScheduler.scheduleClientMonitor(client2); waitForIdle(); assertEquals(mScheduler.getCurrentClient(), client1); assertEquals(Operation.STATE_WAITING_IN_QUEUE, mScheduler.mPendingOperations.getFirst().mState); // Request cancel before the authentication client has started mScheduler.cancelAuthentication(mToken); waitForIdle(); assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING, mScheduler.mPendingOperations.getFirst().mState); // Finish the blocking client. The authentication client should send ERROR_CANCELED client1.getCallback().onClientFinished(client1, true /* success */); waitForIdle(); verify(callback).onError(anyInt(), anyInt(), eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED), eq(0) /* vendorCode */); assertNull(mScheduler.getCurrentClient()); } private BiometricSchedulerProto getDump(boolean clearSchedulerBuffer) throws Exception { return BiometricSchedulerProto.parseFrom(mScheduler.dumpProtoState(clearSchedulerBuffer)); } Loading @@ -293,6 +327,29 @@ public class BiometricSchedulerTest { } } private static class TestAuthenticationClient extends AuthenticationClient<Object> { public TestAuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener) { super(context, lazyDaemon, token, listener, 0 /* targetUserId */, 0 /* operationId */, false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */, TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */, 0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class), false /* isKeyguard */); } @Override protected void stopHalOperation() { } @Override protected void startHalOperation() { } } private static class TestClientMonitor2 extends TestClientMonitor { private final int mProtoEnum; Loading Loading
services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java +19 −7 Original line number Diff line number Diff line Loading @@ -563,14 +563,26 @@ public class BiometricScheduler { final boolean isAuthenticating = mCurrentOperation.mClientMonitor instanceof AuthenticationConsumer; final boolean tokenMatches = mCurrentOperation.mClientMonitor.getToken() == token; if (!isAuthenticating || !tokenMatches) { Slog.w(getTag(), "Not cancelling authentication" + ", current operation : " + mCurrentOperation + ", tokenMatches: " + tokenMatches); return; } if (isAuthenticating && tokenMatches) { Slog.d(getTag(), "Cancelling authentication: " + mCurrentOperation); cancelInternal(mCurrentOperation); } else if (!isAuthenticating) { // Look through the current queue for all authentication clients for the specified // token, and mark them as STATE_WAITING_IN_QUEUE_CANCELING. Note that we're marking // all of them, instead of just the first one, since the API surface currently doesn't // allow us to distinguish between multiple authentication requests from the same // process. However, this generally does not happen anyway, and would be a class of // bugs on its own. for (Operation operation : mPendingOperations) { if (operation.mClientMonitor instanceof AuthenticationConsumer && operation.mClientMonitor.getToken() == token) { Slog.d(getTag(), "Marking " + operation + " as STATE_WAITING_IN_QUEUE_CANCELING"); operation.mState = Operation.STATE_WAITING_IN_QUEUE_CANCELING; } } } } /** Loading
services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java +57 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.IBiometricService; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import androidx.annotation.NonNull; Loading Loading @@ -267,6 +268,39 @@ public class BiometricSchedulerTest { assertEquals(0, bsp.recentOperations.length); } @Test public void testCancelPendingAuth() throws RemoteException { final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class); final TestClientMonitor client1 = new TestClientMonitor(mContext, mToken, lazyDaemon); final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon, mToken, callback); // Add a non-cancellable client, then add the auth client mScheduler.scheduleClientMonitor(client1); mScheduler.scheduleClientMonitor(client2); waitForIdle(); assertEquals(mScheduler.getCurrentClient(), client1); assertEquals(Operation.STATE_WAITING_IN_QUEUE, mScheduler.mPendingOperations.getFirst().mState); // Request cancel before the authentication client has started mScheduler.cancelAuthentication(mToken); waitForIdle(); assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING, mScheduler.mPendingOperations.getFirst().mState); // Finish the blocking client. The authentication client should send ERROR_CANCELED client1.getCallback().onClientFinished(client1, true /* success */); waitForIdle(); verify(callback).onError(anyInt(), anyInt(), eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED), eq(0) /* vendorCode */); assertNull(mScheduler.getCurrentClient()); } private BiometricSchedulerProto getDump(boolean clearSchedulerBuffer) throws Exception { return BiometricSchedulerProto.parseFrom(mScheduler.dumpProtoState(clearSchedulerBuffer)); } Loading @@ -293,6 +327,29 @@ public class BiometricSchedulerTest { } } private static class TestAuthenticationClient extends AuthenticationClient<Object> { public TestAuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener) { super(context, lazyDaemon, token, listener, 0 /* targetUserId */, 0 /* operationId */, false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */, TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */, 0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class), false /* isKeyguard */); } @Override protected void stopHalOperation() { } @Override protected void startHalOperation() { } } private static class TestClientMonitor2 extends TestClientMonitor { private final int mProtoEnum; Loading