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

Commit 2a3c019a authored by Matt Pietal's avatar Matt Pietal
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
Merged-In: I70efe8704931e096698d4a775ee487bb5241d7f1
Change-Id: I70efe8704931e096698d4a775ee487bb5241d7f1
(cherry picked from commit 3395c83b)
parent cfce4992
Loading
Loading
Loading
Loading
+66 −28
Original line number Diff line number Diff line
@@ -247,6 +247,8 @@ public class KeyguardViewMediator extends CoreStartable implements 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.
@@ -398,7 +400,7 @@ public class KeyguardViewMediator extends CoreStartable implements 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;
@@ -688,6 +690,11 @@ public class KeyguardViewMediator extends CoreStartable implements 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);
@@ -723,8 +730,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
            if (targetUserId != ActivityManager.getCurrentUser()) {
                return;
            }
            if (DEBUG) Log.d(TAG, "keyguardDone");
            tryKeyguardDone();
            Log.d(TAG, "keyguardDone: " + targetUserId);
            tryKeyguardDone(targetUserId);
        }

        @Override
@@ -741,18 +748,16 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,

        @Override
        public void keyguardDonePending(boolean strongAuth, int targetUserId) {
            Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardDonePending");
            if (DEBUG) Log.d(TAG, "keyguardDonePending");
            if (targetUserId != ActivityManager.getCurrentUser()) {
                Trace.endSection();
            Log.d(TAG, "keyguardDonePending: " + targetUserId);
            if (targetUserId != KeyguardUpdateMonitor.getCurrentUser()) {
                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();
@@ -770,9 +775,10 @@ public class KeyguardViewMediator extends CoreStartable implements 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();
        }
@@ -1976,7 +1982,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
     * expecting the keyguard to go away when called.
     */
    public void hideWithAnimation(IRemoteAnimationRunner runner) {
        if (!mKeyguardDonePending) {
        if (mKeyguardDonePendingForUser == NO_KEYGUARD_DONE_PENDING) {
            return;
        }

@@ -2199,12 +2205,17 @@ public class KeyguardViewMediator extends CoreStartable implements 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
@@ -2215,7 +2226,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
            mHideAnimationRun = true;
            mHideAnimationRunning = true;
            mKeyguardViewControllerLazy.get()
                    .startPreHideAnimation(mHideAnimationFinishedRunnable);
                    .startPreHideAnimation(new OnHideAnimationFinished(userId));
        }
    }

@@ -2447,6 +2458,15 @@ public class KeyguardViewMediator extends CoreStartable implements 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) {
@@ -2457,12 +2477,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
        }
    };

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

    /**
     * Handle message sent by {@link #hideLocked()}
     * @see #HIDE
@@ -2530,6 +2544,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
            mHiding = false;
            if (mLockPatternUtils.isSecure(currentUserId)) {
                doKeyguardLocked(null);
                mCentralSurfaces.instantCollapseNotificationPanel();
                setShowingLocked(true /* showing */, true /* force */);
            } else {
                resetStateLocked();
                dismiss(null, null);
@@ -2991,7 +3007,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
    }

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

@@ -3147,7 +3163,7 @@ public class KeyguardViewMediator extends CoreStartable implements 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);
@@ -3415,4 +3431,26 @@ public class KeyguardViewMediator extends CoreStartable implements 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();
                mCentralSurfaces.instantCollapseNotificationPanel();
                return;
            }

            tryKeyguardDone(mUserId);
        }
    }
}
+72 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -72,6 +73,7 @@ import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@@ -111,6 +113,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {

    private FalsingCollectorFake mFalsingCollector;

    private @Mock CentralSurfaces mCentralSurfaces;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
@@ -203,6 +207,65 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
                mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
    }

    @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(mCentralSurfaces, never()).instantCollapseNotificationPanel();
    }

    @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(mCentralSurfaces).instantCollapseNotificationPanel();
    }

    private void createAndStartViewMediator() {
        mViewMediator = new KeyguardViewMediator(
                mContext,
@@ -232,5 +295,14 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
                mNotificationShadeWindowControllerLazy,
                () -> mActivityLaunchAnimator);
        mViewMediator.start();

        mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);
    }

    private void setCurrentUser(int userId, boolean isSecure) {
        when(mLockPatternUtils.isSecure(userId)).thenReturn(isSecure);
        mViewMediator.setCurrentUser(userId);
        TestableLooper.get(this).processAllMessages();
        mUiBgExecutor.runAllReady();
    }
}