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

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

Merge "Ensure authentication lifecycle ends for callers" into sc-dev

parents 50ff5ac8 b0551399
Loading
Loading
Loading
Loading
+27 −1
Original line number Original line Diff line number Diff line
@@ -180,7 +180,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
                + ", isBP: " + isBiometricPrompt()
                + ", isBP: " + isBiometricPrompt()
                + ", listener: " + listener
                + ", listener: " + listener
                + ", requireConfirmation: " + mRequireConfirmation
                + ", requireConfirmation: " + mRequireConfirmation
                + ", user: " + getTargetUserId());
                + ", user: " + getTargetUserId()
                + ", clientMonitor: " + toString());


        final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId());
        final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId());
        if (isCryptoOperation()) {
        if (isCryptoOperation()) {
@@ -304,6 +305,11 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
                public void handleLifecycleAfterAuth() {
                public void handleLifecycleAfterAuth() {
                    AuthenticationClient.this.handleLifecycleAfterAuth(true /* authenticated */);
                    AuthenticationClient.this.handleLifecycleAfterAuth(true /* authenticated */);
                }
                }

                @Override
                public void sendAuthenticationCanceled() {
                    sendCancelOnly(listener);
                }
            });
            });
        } else {
        } else {
            // Allow system-defined limit of number of attempts before giving up
            // Allow system-defined limit of number of attempts before giving up
@@ -338,10 +344,30 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
                public void handleLifecycleAfterAuth() {
                public void handleLifecycleAfterAuth() {
                    AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
                    AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
                }
                }

                @Override
                public void sendAuthenticationCanceled() {
                    sendCancelOnly(listener);
                }
            });
            });
        }
        }
    }
    }


    private void sendCancelOnly(@Nullable ClientMonitorCallbackConverter listener) {
        if (listener == null) {
            Slog.e(TAG, "Unable to sendAuthenticationCanceled, listener null");
            return;
        }
        try {
            listener.onError(getSensorId(),
                    getCookie(),
                    BiometricConstants.BIOMETRIC_ERROR_CANCELED,
                    0 /* vendorCode */);
        } catch (RemoteException e) {
            Slog.e(TAG, "Remote exception", e);
        }
    }

    @Override
    @Override
    public void onAcquired(int acquiredInfo, int vendorCode) {
    public void onAcquired(int acquiredInfo, int vendorCode) {
        super.onAcquired(acquiredInfo, vendorCode);
        super.onAcquired(acquiredInfo, vendorCode);
+15 −2
Original line number Original line Diff line number Diff line
@@ -73,6 +73,11 @@ public class CoexCoordinator {
         * from scheduler if auth was successful).
         * from scheduler if auth was successful).
         */
         */
        void handleLifecycleAfterAuth();
        void handleLifecycleAfterAuth();

        /**
         * Requests the owner to notify the caller that authentication was canceled.
         */
        void sendAuthenticationCanceled();
    }
    }


    private static CoexCoordinator sInstance;
    private static CoexCoordinator sInstance;
@@ -356,7 +361,11 @@ public class CoexCoordinator {
    private SuccessfulAuth popSuccessfulFaceAuthIfExists(long currentTimeMillis) {
    private SuccessfulAuth popSuccessfulFaceAuthIfExists(long currentTimeMillis) {
        for (SuccessfulAuth auth : mSuccessfulAuths) {
        for (SuccessfulAuth auth : mSuccessfulAuths) {
            if (currentTimeMillis - auth.mAuthTimestamp >= SUCCESSFUL_AUTH_VALID_DURATION_MS) {
            if (currentTimeMillis - auth.mAuthTimestamp >= SUCCESSFUL_AUTH_VALID_DURATION_MS) {
                Slog.d(TAG, "Removing stale auth: " + auth);
                // TODO(b/193089985): This removes the auth but does not notify the client with
                //  an appropriate lifecycle event (such as ERROR_CANCELED), and violates the
                //  API contract. However, this might be OK for now since the validity duration
                //  is way longer than the time it takes to auth with fingerprint.
                Slog.e(TAG, "Removing stale auth: " + auth);
                mSuccessfulAuths.remove(auth);
                mSuccessfulAuths.remove(auth);
            } else if (auth.mSensorType == SENSOR_TYPE_FACE) {
            } else if (auth.mSensorType == SENSOR_TYPE_FACE) {
                mSuccessfulAuths.remove(auth);
                mSuccessfulAuths.remove(auth);
@@ -367,9 +376,13 @@ public class CoexCoordinator {
    }
    }


    private void removeAndFinishAllFaceFromQueue() {
    private void removeAndFinishAllFaceFromQueue() {
        // Note that these auth are all successful, but have never notified the client (e.g.
        // keyguard). To comply with the authentication lifecycle, we must notify the client that
        // auth is "done". The safest thing to do is to send ERROR_CANCELED.
        for (SuccessfulAuth auth : mSuccessfulAuths) {
        for (SuccessfulAuth auth : mSuccessfulAuths) {
            if (auth.mSensorType == SENSOR_TYPE_FACE) {
            if (auth.mSensorType == SENSOR_TYPE_FACE) {
                Slog.d(TAG, "Removing from queue and finishing: " + auth);
                Slog.d(TAG, "Removing from queue, canceling, and finishing: " + auth);
                auth.mCallback.sendAuthenticationCanceled();
                auth.mCallback.handleLifecycleAfterAuth();
                auth.mCallback.handleLifecycleAfterAuth();
                mSuccessfulAuths.remove(auth);
                mSuccessfulAuths.remove(auth);
            }
            }
+14 −9
Original line number Original line Diff line number Diff line
@@ -255,13 +255,16 @@ public class CoexCoordinatorTest {
        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);


        // For easier reading
        final CoexCoordinator.Callback faceCallback = mCallback;

        mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
        mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
                mCallback);
                faceCallback);
        verify(mCallback, never()).sendHapticFeedback();
        verify(faceCallback, never()).sendHapticFeedback();
        verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
        verify(faceCallback, never()).sendAuthenticationResult(anyBoolean());
        // CoexCoordinator requests the system to hold onto this AuthenticationClient until
        // CoexCoordinator requests the system to hold onto this AuthenticationClient until
        // UDFPS result is known
        // UDFPS result is known
        verify(mCallback, never()).handleLifecycleAfterAuth();
        verify(faceCallback, never()).handleLifecycleAfterAuth();


        // Reset the mock
        // Reset the mock
        CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class);
        CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class);
@@ -274,6 +277,8 @@ public class CoexCoordinatorTest {
            verify(udfpsCallback).sendAuthenticationResult(true /* addAuthTokenIfStrong */);
            verify(udfpsCallback).sendAuthenticationResult(true /* addAuthTokenIfStrong */);
            verify(udfpsCallback).handleLifecycleAfterAuth();
            verify(udfpsCallback).handleLifecycleAfterAuth();


            verify(faceCallback).sendAuthenticationCanceled();

            assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
            assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
        } else {
        } else {
            mCoexCoordinator.onAuthenticationRejected(udfpsRejectedAfterMs, udfpsClient,
            mCoexCoordinator.onAuthenticationRejected(udfpsRejectedAfterMs, udfpsClient,
@@ -281,16 +286,16 @@ public class CoexCoordinatorTest {
            if (udfpsRejectedAfterMs <= CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS) {
            if (udfpsRejectedAfterMs <= CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS) {
                verify(udfpsCallback, never()).sendHapticFeedback();
                verify(udfpsCallback, never()).sendHapticFeedback();


                verify(mCallback).sendHapticFeedback();
                verify(faceCallback).sendHapticFeedback();
                verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
                verify(faceCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
                verify(mCallback).handleLifecycleAfterAuth();
                verify(faceCallback).handleLifecycleAfterAuth();


                assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
                assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
            } else {
            } else {
                assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
                assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());


                verify(mCallback, never()).sendHapticFeedback();
                verify(faceCallback, never()).sendHapticFeedback();
                verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
                verify(faceCallback, never()).sendAuthenticationResult(anyBoolean());


                verify(udfpsCallback).sendHapticFeedback();
                verify(udfpsCallback).sendHapticFeedback();
                verify(udfpsCallback)
                verify(udfpsCallback)