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

Commit 505eb896 authored by Kevin Chyn's avatar Kevin Chyn
Browse files

ClearBiometricRecognized when user switches

User unlock states should be cleared whenever user switches. Otherwise,
it's possible for the following sequence of events

1) Unlock first user via biometrics
2) Do not dismiss keyguard, switch to second user
3) Switch back to first user - can unlock without authenticating

Fixes: 151906507

Test: Repeat steps above, does not occur anymore
Test: atest KeyguardUpdateMonitorTest
Change-Id: I1d8e5867a18a680e85be8c335f09d4cb4209612e
parent 4f9ab82c
Loading
Loading
Loading
Loading
+34 −5
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    private static final boolean DEBUG = KeyguardConstants.DEBUG;
    private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
    private static final boolean DEBUG_FACE = true;
    private static final boolean DEBUG_SPEW = false;
    private static final int LOW_BATTERY_THRESHOLD = 20;

    private static final String ACTION_FACE_UNLOCK_STARTED
@@ -324,7 +325,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                }
            };

    private class BiometricAuthenticated {
    @VisibleForTesting
    static class BiometricAuthenticated {
        private final boolean mAuthenticated;
        private final boolean mIsStrongBiometric;

@@ -338,11 +340,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
    private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
    private SparseBooleanArray mUserTrustIsUsuallyManaged = new SparseBooleanArray();
    private SparseArray<BiometricAuthenticated> mUserFingerprintAuthenticated = new SparseArray<>();
    private SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>();
    private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
    private Map<Integer, Intent> mSecondaryLockscreenRequirement = new HashMap<Integer, Intent>();

    @VisibleForTesting
    SparseArray<BiometricAuthenticated> mUserFingerprintAuthenticated = new SparseArray<>();
    @VisibleForTesting
    SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>();

    private static int sCurrentUser;
    private Runnable mUpdateBiometricListeningState = this::updateBiometricListeningState;

@@ -1850,11 +1855,33 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab

        // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
        // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
        return (mBouncer || mAuthInterruptActive || awakeKeyguard || shouldListenForFaceAssistant())
        final boolean shouldListen =
                (mBouncer || mAuthInterruptActive || awakeKeyguard
                        || shouldListenForFaceAssistant())
                && !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer
                && !mKeyguardGoingAway && mFaceSettingEnabledForUser.get(user) && !mLockIconPressed
                && strongAuthAllowsScanning && mIsPrimaryUser
                && !mSecureCameraLaunched;

        // Too chatty, but very useful when debugging issues.
        if (DEBUG_SPEW) {
            Log.v(TAG, "shouldListenForFace(" + user + ")=" + shouldListen + "... "
                    + ", mBouncer: " + mBouncer
                    + ", mAuthInterruptActive: " + mAuthInterruptActive
                    + ", awakeKeyguard: " + awakeKeyguard
                    + ", shouldListenForFaceAssistant: " + shouldListenForFaceAssistant()
                    + ", mSwitchingUser: " + mSwitchingUser
                    + ", isFaceDisabled(" + user + "): " + isFaceDisabled(user)
                    + ", becauseCannotSkipBouncer: " + becauseCannotSkipBouncer
                    + ", mKeyguardGoingAway: " + mKeyguardGoingAway
                    + ", mFaceSettingEnabledForUser(" + user + "): "
                            + mFaceSettingEnabledForUser.get(user)
                    + ", mLockIconPressed: " + mLockIconPressed
                    + ", strongAuthAllowsScanning: " + strongAuthAllowsScanning
                    + ", isPrimaryUser: " + mIsPrimaryUser
                    + ", mSecureCameraLaunched: " + mSecureCameraLaunched);
        }
        return shouldListen;
    }

    /**
@@ -2049,8 +2076,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    /**
     * Handle {@link #MSG_USER_SWITCHING}
     */
    private void handleUserSwitching(int userId, IRemoteCallback reply) {
    @VisibleForTesting
    void handleUserSwitching(int userId, IRemoteCallback reply) {
        Assert.isMainThread();
        clearBiometricRecognized();
        mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId));
        for (int i = 0; i < mCallbacks.size(); i++) {
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+20 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.UserHandle;
import android.os.UserManager;
import android.telephony.ServiceState;
@@ -63,6 +64,7 @@ import android.testing.TestableContext;
import android.testing.TestableLooper;

import com.android.internal.telephony.TelephonyIntents;
import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
@@ -505,6 +507,24 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isFalse();
    }

    @Test
    public void testBiometricsCleared_whenUserSwitches() throws Exception {
        final IRemoteCallback reply = new IRemoteCallback.Stub() {
            @Override
            public void sendResult(Bundle data) {} // do nothing
        };
        final BiometricAuthenticated dummyAuthentication =
                new BiometricAuthenticated(true /* authenticated */, true /* strong */);
        mKeyguardUpdateMonitor.mUserFaceAuthenticated.put(0 /* user */, dummyAuthentication);
        mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.put(0 /* user */, dummyAuthentication);
        assertThat(mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.size()).isEqualTo(1);
        assertThat(mKeyguardUpdateMonitor.mUserFaceAuthenticated.size()).isEqualTo(1);

        mKeyguardUpdateMonitor.handleUserSwitching(10 /* user */, reply);
        assertThat(mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.size()).isEqualTo(0);
        assertThat(mKeyguardUpdateMonitor.mUserFaceAuthenticated.size()).isEqualTo(0);
    }

    @Test
    public void testGetUserCanSkipBouncer_whenTrust() {
        int user = KeyguardUpdateMonitor.getCurrentUser();