Cancel acquisition client in scheduler

If acquisition client has been cancelled and the cancellation not been propagated to the scheduler, force cancel the client in scheduler to avoid it from being hung.

Test: atest BiometricSchedulerTest
Fixes: 263527633
Change-Id: I2c4167950aada9ae564fc44246b4ed83e8444a20
This commit is contained in:
Diya Bera
2023-06-13 09:55:58 -07:00
parent b2757069c8
commit cb08949a3f
3 changed files with 67 additions and 0 deletions

View File

@@ -210,4 +210,8 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement
public boolean isInterruptable() {
return true;
}
public boolean isAlreadyCancelled() {
return mAlreadyCancelled;
}
}

View File

@@ -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 */);

View File

@@ -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<Object> 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<Object> 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<Object> lazyDaemon = () -> mock(Object.class);