Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d4c00058 authored by Kevin Chyn's avatar Kevin Chyn Committed by Android (Google) Code Review
Browse files

Merge "Check pending queue for cancelAuthentication" into sc-dev

parents c78898c3 82b6469a
Loading
Loading
Loading
Loading
+19 −7
Original line number Diff line number Diff line
@@ -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;
                }
            }
        }
    }

    /**
+57 −0
Original line number Diff line number Diff line
@@ -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;