Check pending queue for cancelAuthentication
If cancelAuthentication is requested but actual authentication has not started yet (e.g. a previous non-cancelable operation such as updateActiveGroup or getAuthenticatorId is still running), look through the pending queue and mark all matched authentication clients as STATE_WAITING_IN_QUEUE_CANCELING. Test: atest BiometricSchedulerTest Fixes: 178105328 Change-Id: I755359adbdcda7f054135a190426b4a78a7a5125
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
cancelInternal(mCurrentOperation);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user