diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java index 46c77e8a82f22..aa6a0f1bb55f0 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java @@ -210,4 +210,8 @@ public abstract class AcquisitionClient extends HalClientMonitor implement public boolean isInterruptable() { return true; } + + public boolean isAlreadyCancelled() { + return mAlreadyCancelled; + } } 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 7fa4d6ce4d492..78c38089e8032 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java @@ -268,6 +268,14 @@ public class BiometricScheduler { return; } + if (mCurrentOperation.isAcquisitionOperation()) { + AcquisitionClient client = (AcquisitionClient) mCurrentOperation.getClientMonitor(); + if (client.isAlreadyCancelled()) { + mCurrentOperation.cancel(mHandler, mInternalCallback); + return; + } + } + if (mGestureAvailabilityDispatcher != null && mCurrentOperation.isAcquisitionOperation()) { mGestureAvailabilityDispatcher.markSensorActive( mCurrentOperation.getSensorId(), true /* active */); 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 e9d82696affc6..89299002a227f 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 @@ -19,6 +19,8 @@ package com.android.server.biometrics.sensors; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS; +import static com.google.common.truth.Truth.assertThat; + import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; @@ -405,6 +407,59 @@ public class BiometricSchedulerTest { testCancelsEnrollWhenRequestId(10L, 20, false /* started */); } + @Test + public void testCancelAuthenticationClientWithoutStarting() { + final Supplier lazyDaemon = () -> mock(Object.class); + final TestHalClientMonitor client1 = new TestHalClientMonitor(mContext, mToken, lazyDaemon); + final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); + final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon, + mToken, callback, mBiometricContext); + + //Schedule authentication client to the pending queue + mScheduler.scheduleClientMonitor(client1); + mScheduler.scheduleClientMonitor(client2); + waitForIdle(); + + assertThat(mScheduler.getCurrentClient()).isEqualTo(client1); + + client2.cancel(); + waitForIdle(); + + assertThat(client2.isAlreadyCancelled()).isTrue(); + + client1.getCallback().onClientFinished(client1, false); + waitForIdle(); + + assertThat(mScheduler.getCurrentClient()).isNull(); + } + + @Test + public void testCancelAuthenticationClientWithoutStarting_whenAppCrashes() { + final Supplier lazyDaemon = () -> mock(Object.class); + final TestHalClientMonitor client1 = new TestHalClientMonitor(mContext, mToken, lazyDaemon); + final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); + final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon, + mToken, callback, mBiometricContext); + + //Schedule authentication client to the pending queue + mScheduler.scheduleClientMonitor(client1); + mScheduler.scheduleClientMonitor(client2); + waitForIdle(); + + assertThat(mScheduler.getCurrentClient()).isEqualTo(client1); + + //App crashes + client2.binderDied(); + waitForIdle(); + + assertThat(client2.isAlreadyCancelled()).isTrue(); + + client1.getCallback().onClientFinished(client1, false); + waitForIdle(); + + assertThat(mScheduler.getCurrentClient()).isNull(); + } + private void testCancelsEnrollWhenRequestId(@Nullable Long requestId, long cancelRequestId, boolean started) { final Supplier lazyDaemon = () -> mock(Object.class);