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

Commit fa621690 authored by Matt Pietal's avatar Matt Pietal Committed by Mohammed Althaf T
Browse files

Validate user on biometric auth and keyguard done

On user switching, it is possible to start a chain of events
that validate the prior user before user switching is complete,
notably on biomtetric auth success and the tryKeyguarDone paths.
The latter is a runnable that can be scheduled after dismiss
animations run, but if the user was changed in the middle, it
is possible to dismiss the prior keyguard.

Revalidate the user at multiple points, and reset the keyguard
when the user id mismatch is detected.

Bug: 413380719
Test: atest KeyguardViewMediatorTest
Flag: EXEMPT bugfix
(cherry picked from commit 3395c83b)
Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:b955515f51a4bfdde9595486c93866f9e094222f
Merged-In: I70efe8704931e096698d4a775ee487bb5241d7f1
Change-Id: I70efe8704931e096698d4a775ee487bb5241d7f1
parent 4efe45f8
Loading
Loading
Loading
Loading
+65 −27
Original line number Diff line number Diff line
@@ -259,6 +259,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,

    private static final int UNOCCLUDE_ANIMATION_DURATION = 250;

    private static final int NO_KEYGUARD_DONE_PENDING = -10000;

    /**
     * How far down to animate the unoccluding activity, in terms of percent of the activity's
     * height.
@@ -415,7 +417,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
    private boolean mWaitingUntilKeyguardVisible = false;
    private final LockPatternUtils mLockPatternUtils;
    private final BroadcastDispatcher mBroadcastDispatcher;
    private boolean mKeyguardDonePending = false;
    private int mKeyguardDonePendingForUser = NO_KEYGUARD_DONE_PENDING;
    private boolean mHideAnimationRun = false;
    private boolean mHideAnimationRunning = false;
    private boolean mIsKeyguardExitAnimationCanceled = false;
@@ -706,6 +708,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        @Override
        public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
                boolean isStrongBiometric) {
            if (userId != KeyguardUpdateMonitor.getCurrentUser()) {
                Log.w(TAG, "onBiometricAuthenticated() invoked for userId: " + userId + ", current "
                        + "userId: " + KeyguardUpdateMonitor.getCurrentUser());
                return;
            }
            if (mLockPatternUtils.isSecure(userId)) {
                mLockPatternUtils.getDevicePolicyManager().reportSuccessfulBiometricAttempt(
                        userId);
@@ -741,8 +748,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            if (targetUserId != KeyguardUpdateMonitor.getCurrentUser()) {
                return;
            }
            if (DEBUG) Log.d(TAG, "keyguardDone");
            tryKeyguardDone();
            Log.d(TAG, "keyguardDone: " + targetUserId);
            tryKeyguardDone(targetUserId);
        }

        @Override
@@ -759,18 +766,16 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,

        @Override
        public void keyguardDonePending(boolean strongAuth, int targetUserId) {
            Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardDonePending");
            if (DEBUG) Log.d(TAG, "keyguardDonePending");
            Log.d(TAG, "keyguardDonePending: " + targetUserId);
            if (targetUserId != KeyguardUpdateMonitor.getCurrentUser()) {
                Trace.endSection();
                return;
            }

            mKeyguardDonePending = true;
            Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardDonePending");
            mKeyguardDonePendingForUser = targetUserId;
            mHideAnimationRun = true;
            mHideAnimationRunning = true;
            mKeyguardViewControllerLazy.get()
                    .startPreHideAnimation(mHideAnimationFinishedRunnable);
                    .startPreHideAnimation(new OnHideAnimationFinished(targetUserId));
            mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_PENDING_TIMEOUT,
                    KEYGUARD_DONE_PENDING_TIMEOUT_MS);
            Trace.endSection();
@@ -788,9 +793,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        @Override
        public void readyForKeyguardDone() {
            Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#readyForKeyguardDone");
            if (mKeyguardDonePending) {
                mKeyguardDonePending = false;
                tryKeyguardDone();
            if (mKeyguardDonePendingForUser != NO_KEYGUARD_DONE_PENDING) {
                int user = mKeyguardDonePendingForUser;
                mKeyguardDonePendingForUser = NO_KEYGUARD_DONE_PENDING;
                tryKeyguardDone(user);
            }
            Trace.endSection();
        }
@@ -2126,7 +2132,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
     * expecting the keyguard to go away when called.
     */
    public void hideWithAnimation(IRemoteAnimationRunner runner) {
        if (!mKeyguardDonePending) {
        if (mKeyguardDonePendingForUser == NO_KEYGUARD_DONE_PENDING) {
            return;
        }

@@ -2352,12 +2358,17 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        }
    };

    private void tryKeyguardDone() {
        if (DEBUG) {
            Log.d(TAG, "tryKeyguardDone: pending - " + mKeyguardDonePending + ", animRan - "
                    + mHideAnimationRun + " animRunning - " + mHideAnimationRunning);
    private void tryKeyguardDone(int userId) {
        String logUserId;
        if (mKeyguardDonePendingForUser == NO_KEYGUARD_DONE_PENDING) {
            logUserId = "NO_KEYGUARD_DONE_PENDING";
        } else {
            logUserId = "" + mKeyguardDonePendingForUser;
        }
        if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) {
        Log.d(TAG, "tryKeyguardDone: pendingForUser - " + logUserId
                + ", animRan - " + mHideAnimationRun + " animRunning - " + mHideAnimationRunning);
        if (mKeyguardDonePendingForUser == NO_KEYGUARD_DONE_PENDING && mHideAnimationRun
                && !mHideAnimationRunning) {
            handleKeyguardDone();
        } else if (mSurfaceBehindRemoteAnimationRunning) {
            // We're already running the keyguard exit animation, likely due to an in-progress swipe
@@ -2368,7 +2379,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            mHideAnimationRun = true;
            mHideAnimationRunning = true;
            mKeyguardViewControllerLazy.get()
                    .startPreHideAnimation(mHideAnimationFinishedRunnable);
                    .startPreHideAnimation(new OnHideAnimationFinished(userId));
        }
    }

@@ -2606,6 +2617,15 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            // will be in order.
            final int keyguardFlag = flags;
            mUiBgExecutor.execute(() -> {
                int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
                if (mGoingAwayRequestedForUserId != currentUserId) {
                    Log.e(TAG, "Not executing goingAwayRunnable() due to userId mismatch. "
                            + "Requested: " + mGoingAwayRequestedForUserId + ", current: "
                            + currentUserId);
                    mUpdateMonitor.setKeyguardGoingAway(false);
                    mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false);
                    return;
                }
                try {
                    ActivityTaskManager.getService().keyguardGoingAway(keyguardFlag);
                } catch (RemoteException e) {
@@ -2616,12 +2636,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        }
    };

    private final Runnable mHideAnimationFinishedRunnable = () -> {
        Log.e(TAG, "mHideAnimationFinishedRunnable#run");
        mHideAnimationRunning = false;
        tryKeyguardDone();
    };

    /**
     * Handle message sent by {@link #hideLocked()}
     * @see #HIDE
@@ -2696,6 +2710,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            mHiding = false;
            if (mLockPatternUtils.isSecure(currentUserId)) {
                doKeyguardLocked(null);
                mShadeController.get().instantCollapseShade();
                setShowingLocked(true /* showing */, true /* force */);
            } else {
                resetStateLocked();
                dismiss(null, null);
@@ -3185,7 +3201,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
    }

    private void resetKeyguardDonePendingLocked() {
        mKeyguardDonePending = false;
        mKeyguardDonePendingForUser = NO_KEYGUARD_DONE_PENDING;
        mHandler.removeMessages(KEYGUARD_DONE_PENDING_TIMEOUT);
    }

@@ -3340,7 +3356,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        pw.print("  mDozing: "); pw.println(mDozing);
        pw.print("  mAodShowing: "); pw.println(mAodShowing);
        pw.print("  mWaitingUntilKeyguardVisible: "); pw.println(mWaitingUntilKeyguardVisible);
        pw.print("  mKeyguardDonePending: "); pw.println(mKeyguardDonePending);
        pw.print("  mKeyguardDonePendingForUser: "); pw.println(mKeyguardDonePendingForUser);
        pw.print("  mHideAnimationRun: "); pw.println(mHideAnimationRun);
        pw.print("  mPendingReset: "); pw.println(mPendingReset);
        pw.print("  mPendingLock: "); pw.println(mPendingLock);
@@ -3611,4 +3627,26 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            mRemoteCallback = remoteCallback;
        }
    }

    private class OnHideAnimationFinished implements Runnable {
        private final int mUserId;
        public OnHideAnimationFinished(int userId) {
            mUserId = userId;
        }

        public void run() {
            Log.d(TAG, "OnHideAnimationFinished.run(" + mUserId + ")");
            mHideAnimationRunning = false;
            int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
            if (mUserId != currentUserId) {
                Log.e(TAG, "Not executing OnHideAnimationFinished.run() due to userId mismatch. "
                        + "Requested: " + mUserId + ", current: " + currentUserId);
                resetStateLocked();
                mShadeController.get().instantCollapseShade();
                return;
            }

            tryKeyguardDone(mUserId);
        }
    }
}
+59 −0
Original line number Diff line number Diff line
@@ -515,6 +515,65 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
        verify(mStatusBarKeyguardViewManager, never()).reset(anyBoolean());
    }

    @Test
    public void biometricAuthSuccessForCurrentUserDoesProceed() {
        final int currentUser = 25;
        setCurrentUser(currentUser, true);

        mViewMediator.mUpdateCallback.onBiometricAuthenticated(currentUser, null, false);

        verify(mDevicePolicyManager).reportSuccessfulBiometricAttempt(currentUser);
    }

    @Test
    public void biometricAuthSuccessForDifferentUserDoesNotProceed() {
        final int newUser = 40;
        setCurrentUser(newUser, true);

        final int oldUser = 25;
        mViewMediator.mUpdateCallback.onBiometricAuthenticated(oldUser, null, false);

        verify(mDevicePolicyManager, never()).reportSuccessfulBiometricAttempt(anyInt());
    }

    @Test
    public void testDonePendingExecutesOnHideAnimationFinished() {
        final int currentUser = 25;
        setCurrentUser(currentUser, true);
        mViewMediator.mViewMediatorCallback.keyguardDonePending(true, currentUser);

        final ArgumentCaptor<Runnable> onHideAnimationFinished =
                ArgumentCaptor.forClass(Runnable.class);
        verify(mStatusBarKeyguardViewManager).startPreHideAnimation(
                onHideAnimationFinished.capture());

        onHideAnimationFinished.getValue().run();

        // This is executed when the user is incorrect. Should not be called
        verify(mShadeController, never()).instantCollapseShade();
    }

    @Test
    public void testDonePendingExecutesOnHideAnimationFinishedButTerminatesWhenUserHasChanged() {
        final int currentUser = 25;
        setCurrentUser(currentUser, true);
        mViewMediator.mViewMediatorCallback.keyguardDonePending(true, currentUser);

        final ArgumentCaptor<Runnable> onHideAnimationFinished =
                ArgumentCaptor.forClass(Runnable.class);
        verify(mStatusBarKeyguardViewManager).startPreHideAnimation(
                onHideAnimationFinished.capture());

        // User switched before runnable could execute
        final int newUser = 40;
        setCurrentUser(newUser, true);

        onHideAnimationFinished.getValue().run();

        // This is executed when the user is incorrect
        verify(mShadeController).instantCollapseShade();
    }

    private void createAndStartViewMediator() {
        mViewMediator = new KeyguardViewMediator(
                mContext,