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

Commit 5e844042 authored by Beverly's avatar Beverly Committed by Beverly Tai
Browse files

On strongAuthChanges, update fp & face states

Previously, we relied on other state to update which
would trigger updateBiometricListeningState. Instead
of relying on other triggers, directly update
the biometric listening state if strong auth
or non-strong auth allowed states change.

Don't run face auth or detect if device is locked down by the
user. However, if bypass is enabled and the other strongauth
requirements are triggered (ie: idle timeout, timeout, encrypted,
dpm lockdown, after boot), then run detectFace if its supported.

Bug: 259908246
Bug: 258513069
Bug: 260682144
Test: atest KeyguardUpdateMonitorTest
Change-Id: If03a1525832dfb8366c36757ebc84c0dead51b9f
parent 129a1053
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -48,11 +48,13 @@ import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_INIT
import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_OCCLUSION_CHANGED
import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_RESET
import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_VISIBILITY_CHANGED
import com.android.keyguard.InternalFaceAuthReasons.NON_STRONG_BIOMETRIC_ALLOWED_CHANGED
import com.android.keyguard.InternalFaceAuthReasons.OCCLUDING_APP_REQUESTED
import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN
import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN
import com.android.keyguard.InternalFaceAuthReasons.RETRY_AFTER_HW_UNAVAILABLE
import com.android.keyguard.InternalFaceAuthReasons.STARTED_WAKING_UP
import com.android.keyguard.InternalFaceAuthReasons.STRONG_AUTH_ALLOWED_CHANGED
import com.android.keyguard.InternalFaceAuthReasons.TRUST_DISABLED
import com.android.keyguard.InternalFaceAuthReasons.TRUST_ENABLED
import com.android.keyguard.InternalFaceAuthReasons.USER_SWITCHING
@@ -121,6 +123,9 @@ private object InternalFaceAuthReasons {
    const val FACE_AUTHENTICATED = "Face auth started/stopped because face is authenticated"
    const val BIOMETRIC_ENABLED =
        "Face auth started/stopped because biometric is enabled on keyguard"
    const val STRONG_AUTH_ALLOWED_CHANGED = "Face auth stopped because strong auth allowed changed"
    const val NON_STRONG_BIOMETRIC_ALLOWED_CHANGED =
        "Face auth stopped because non strong biometric allowed changed"
}

/**
@@ -204,7 +209,11 @@ constructor(private val id: Int, val reason: String, var extraInfo: Int = 0) :
    @UiEvent(doc = FACE_AUTHENTICATED)
    FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED(1187, FACE_AUTHENTICATED),
    @UiEvent(doc = BIOMETRIC_ENABLED)
    FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD(1188, BIOMETRIC_ENABLED);
    FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD(1188, BIOMETRIC_ENABLED),
    @UiEvent(doc = STRONG_AUTH_ALLOWED_CHANGED)
    FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED(1255, STRONG_AUTH_ALLOWED_CHANGED),
    @UiEvent(doc = NON_STRONG_BIOMETRIC_ALLOWED_CHANGED)
    FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED(1256, NON_STRONG_BIOMETRIC_ALLOWED_CHANGED);

    override fun getId(): Int = this.id

+4 −5
Original line number Diff line number Diff line
@@ -53,17 +53,17 @@ data class KeyguardFaceListenModel(
    val biometricSettingEnabledForUser: Boolean,
    val bouncerFullyShown: Boolean,
    val faceAndFpNotAuthenticated: Boolean,
    val faceAuthAllowed: Boolean,
    val faceDisabled: Boolean,
    val faceLockedOut: Boolean,
    val fpLockedOut: Boolean,
    val goingToSleep: Boolean,
    val keyguardAwake: Boolean,
    val keyguardGoingAway: Boolean,
    val listeningForFaceAssistant: Boolean,
    val occludingAppRequestingFaceAuth: Boolean,
    val primaryUser: Boolean,
    val scanningAllowedByStrongAuth: Boolean,
    val secureCameraLaunched: Boolean,
    val supportsDetect: Boolean,
    val switchingUser: Boolean,
    val udfpsBouncerShowing: Boolean,
    val udfpsFingerDown: Boolean,
@@ -79,9 +79,8 @@ data class KeyguardActiveUnlockModel(
    // keep sorted
    val awakeKeyguard: Boolean,
    val authInterruptActive: Boolean,
    val encryptedOrTimedOut: Boolean,
    val fpLockout: Boolean,
    val lockDown: Boolean,
    val fpLockedOut: Boolean,
    val primaryAuthRequired: Boolean,
    val switchingUser: Boolean,
    val triggerActiveUnlockForAssistant: Boolean,
    val userCanDismissLockScreen: Boolean
+62 −65
Original line number Diff line number Diff line
@@ -34,9 +34,9 @@ import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.keyguard.FaceAuthReasonKt.apiRequestReasonToUiEvent;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_DREAM_STARTED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP;
@@ -65,6 +65,7 @@ import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_FACE_AUT
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_KEYGUARD_INIT;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STARTED_WAKING_UP;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING;
import static com.android.systemui.DejankUtils.whitelistIpcs;

@@ -170,7 +171,6 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import javax.inject.Inject;
@@ -1401,6 +1401,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        }
    }

    /**
     * Whether the user locked down the device. This doesn't include device policy manager lockdown.
     */
    public boolean isUserInLockdown(int userId) {
        return containsFlag(mStrongAuthTracker.getStrongAuthForUser(userId),
                STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
@@ -1432,7 +1435,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        return mStrongAuthTracker;
    }

    private void notifyStrongAuthStateChanged(int userId) {
    @VisibleForTesting
    void notifyStrongAuthAllowedChanged(int userId) {
        Assert.isMainThread();
        for (int i = 0; i < mCallbacks.size(); i++) {
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1440,6 +1444,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                cb.onStrongAuthStateChanged(userId);
            }
        }
        if (userId == getCurrentUser()) {
            FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED.setExtraInfo(
                    mStrongAuthTracker.getStrongAuthForUser(getCurrentUser()));

            // Strong auth is only reset when primary auth is used to enter the device,
            // so we only check whether to stop biometric listening states here
            updateBiometricListeningState(
                    BIOMETRIC_ACTION_STOP, FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED);
        }
    }

    private void notifyLockedOutStateChanged(BiometricSourceType type) {
@@ -1451,8 +1464,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
            }
        }
    }

    private void notifyNonStrongBiometricStateChanged(int userId) {
    @VisibleForTesting
    void notifyNonStrongBiometricAllowedChanged(int userId) {
        Assert.isMainThread();
        for (int i = 0; i < mCallbacks.size(); i++) {
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1460,6 +1473,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                cb.onNonStrongBiometricAllowedChanged(userId);
            }
        }
        if (userId == getCurrentUser()) {
            FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED.setExtraInfo(
                    mStrongAuthTracker.isNonStrongBiometricAllowedAfterIdleTimeout(
                            getCurrentUser()) ? -1 : 1);

            // This is only reset when primary auth is used to enter the device, so we only check
            // whether to stop biometric listening states here
            updateBiometricListeningState(BIOMETRIC_ACTION_STOP,
                    FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED);
        }
    }

    private void dispatchErrorMessage(CharSequence message) {
@@ -1805,16 +1828,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        }
    }

    public static class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
        private final Consumer<Integer> mStrongAuthRequiredChangedCallback;
        private final Consumer<Integer> mNonStrongBiometricAllowedChanged;

        public StrongAuthTracker(Context context,
                Consumer<Integer> strongAuthRequiredChangedCallback,
                Consumer<Integer> nonStrongBiometricAllowedChanged) {
    /**
     * Updates callbacks when strong auth requirements change.
     */
    public class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
        public StrongAuthTracker(Context context) {
            super(context);
            mStrongAuthRequiredChangedCallback = strongAuthRequiredChangedCallback;
            mNonStrongBiometricAllowedChanged = nonStrongBiometricAllowedChanged;
        }

        public boolean isUnlockingWithBiometricAllowed(boolean isStrongBiometric) {
@@ -1830,7 +1849,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab

        @Override
        public void onStrongAuthRequiredChanged(int userId) {
            mStrongAuthRequiredChangedCallback.accept(userId);
            notifyStrongAuthAllowedChanged(userId);
        }

        // TODO(b/247091681): Renaming the inappropriate onIsNonStrongBiometricAllowedChanged
@@ -1838,7 +1857,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        //  Strong-Auth
        @Override
        public void onIsNonStrongBiometricAllowedChanged(int userId) {
            mNonStrongBiometricAllowedChanged.accept(userId);
            notifyNonStrongBiometricAllowedChanged(userId);
        }
    }

@@ -1999,8 +2018,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        mUserTracker = userTracker;
        mTelephonyListenerManager = telephonyListenerManager;
        mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
        mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged,
                this::notifyNonStrongBiometricStateChanged);
        mStrongAuthTracker = new StrongAuthTracker(context);
        mBackgroundExecutor = backgroundExecutor;
        mBroadcastDispatcher = broadcastDispatcher;
        mInteractionJankMonitor = interactionJankMonitor;
@@ -2575,24 +2593,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                || !mLockPatternUtils.isSecure(user);

        // Don't trigger active unlock if fp is locked out
        final boolean fpLockedout = mFingerprintLockedOut || mFingerprintLockedOutPermanent;
        final boolean fpLockedOut = mFingerprintLockedOut || mFingerprintLockedOutPermanent;

        // Don't trigger active unlock if primary auth is required
        final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
        final boolean isLockDown =
                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
        final boolean isEncryptedOrTimedOut =
                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
        final boolean primaryAuthRequired = !isUnlockingWithBiometricAllowed(true);

        final boolean shouldTriggerActiveUnlock =
                (mAuthInterruptActive || triggerActiveUnlockForAssistant || awakeKeyguard)
                        && !mSwitchingUser
                        && !userCanDismissLockScreen
                        && !fpLockedout
                        && !isLockDown
                        && !isEncryptedOrTimedOut
                        && !fpLockedOut
                        && !primaryAuthRequired
                        && !mKeyguardGoingAway
                        && !mSecureCameraLaunched;

@@ -2604,9 +2615,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                        shouldTriggerActiveUnlock,
                        awakeKeyguard,
                        mAuthInterruptActive,
                        isEncryptedOrTimedOut,
                        fpLockedout,
                        isLockDown,
                        fpLockedOut,
                        primaryAuthRequired,
                        mSwitchingUser,
                        triggerActiveUnlockForAssistant,
                        userCanDismissLockScreen));
@@ -2658,7 +2668,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                        && !fingerprintDisabledForUser
                        && (!mKeyguardGoingAway || !mDeviceInteractive)
                        && mIsPrimaryUser
                        && biometricEnabledForUser;
                        && biometricEnabledForUser
                        && !isUserInLockdown(user);
        final boolean strongerAuthRequired = !isUnlockingWithFingerprintAllowed();
        final boolean isSideFps = isSfpsSupported() && isSfpsEnrolled();
        final boolean shouldListenBouncerState =
@@ -2720,14 +2731,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        final boolean awakeKeyguard = isKeyguardVisible() && mDeviceInteractive
                && !statusBarShadeLocked;
        final int user = getCurrentUser();
        final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
        final boolean isLockDown =
                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
        final boolean isEncryptedOrTimedOut =
                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
        final boolean fpLockedOut = isFingerprintLockedOut();
        final boolean faceAuthAllowed = isUnlockingWithBiometricAllowed(FACE);
        final boolean canBypass = mKeyguardBypassController != null
                && mKeyguardBypassController.canBypass();
        // There's no reason to ask the HAL for authentication when the user can dismiss the
@@ -2735,20 +2739,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        // the lock screen even when TrustAgents are keeping the device unlocked.
        final boolean userNotTrustedOrDetectionIsNeeded = !getUserHasTrust(user) || canBypass;

        // Scan even when encrypted or timeout to show a preemptive bouncer when bypassing.
        // Lock-down mode shouldn't scan, since it is more explicit.
        boolean strongAuthAllowsScanning = (!isEncryptedOrTimedOut || canBypass
                && !mPrimaryBouncerFullyShown);

        // If the device supports face detection (without authentication) and bypass is enabled,
        // allow face scanning to happen if the device is in lockdown mode.
        // Otherwise, prevent scanning.
        final boolean supportsDetectOnly = !mFaceSensorProperties.isEmpty()
                && canBypass
                && mFaceSensorProperties.get(0).supportsFaceDetection;
        if (isLockDown && !supportsDetectOnly) {
            strongAuthAllowsScanning = false;
        }
        // If the device supports face detection (without authentication), if bypass is enabled,
        // allow face detection to happen even if stronger auth is required. When face is detected,
        // we show the bouncer. However, if the user manually locked down the device themselves,
        // never attempt to detect face.
        final boolean supportsDetect = !mFaceSensorProperties.isEmpty()
                && mFaceSensorProperties.get(0).supportsFaceDetection
                && canBypass && !mPrimaryBouncerIsOrWillBeShowing
                && !isUserInLockdown(user);
        final boolean faceAuthAllowedOrDetectionIsNeeded = faceAuthAllowed || supportsDetect;

        // If the face or fp has recently been authenticated do not attempt to authenticate again.
        final boolean faceAndFpNotAuthenticated = !getUserUnlockedWithBiometric(user);
@@ -2769,14 +2768,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                        || mUdfpsBouncerShowing)
                && !mSwitchingUser && !faceDisabledForUser && userNotTrustedOrDetectionIsNeeded
                && !mKeyguardGoingAway && biometricEnabledForUser
                && strongAuthAllowsScanning && mIsPrimaryUser
                && faceAuthAllowedOrDetectionIsNeeded && mIsPrimaryUser
                && (!mSecureCameraLaunched || mOccludingAppRequestingFace)
                && faceAndFpNotAuthenticated
                && !mGoingToSleep
                // We only care about fp locked out state and not face because we still trigger
                // face auth even when face is locked out to show the user a message that face
                // unlock was supposed to run but didn't
                && !fpLockedOut;
                && !mGoingToSleep;

        // Aggregate relevant fields for debug logging.
        maybeLogListenerModelData(
@@ -2788,17 +2783,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                    biometricEnabledForUser,
                    mPrimaryBouncerFullyShown,
                    faceAndFpNotAuthenticated,
                    faceAuthAllowed,
                    faceDisabledForUser,
                    isFaceLockedOut(),
                    fpLockedOut,
                    mGoingToSleep,
                    awakeKeyguard,
                    mKeyguardGoingAway,
                    shouldListenForFaceAssistant,
                    mOccludingAppRequestingFace,
                    mIsPrimaryUser,
                    strongAuthAllowsScanning,
                    mSecureCameraLaunched,
                    supportsDetect,
                    mSwitchingUser,
                    mUdfpsBouncerShowing,
                    isUdfpsFingerDown,
@@ -2902,9 +2897,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
            // This would need to be updated for multi-sensor devices
            final boolean supportsFaceDetection = !mFaceSensorProperties.isEmpty()
                    && mFaceSensorProperties.get(0).supportsFaceDetection;
            if (isEncryptedOrLockdown(userId) && supportsFaceDetection) {
            if (!isUnlockingWithBiometricAllowed(FACE) && supportsFaceDetection) {
                mLogger.v("startListeningForFace - detect");
                mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
            } else {
                mLogger.v("startListeningForFace - authenticate");
                final boolean isBypassEnabled = mKeyguardBypassController != null
                        && mKeyguardBypassController.isBypassEnabled();
                mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal,
+2 −2
Original line number Diff line number Diff line
@@ -87,17 +87,17 @@ private fun faceModel(user: Int) = KeyguardFaceListenModel(
    biometricSettingEnabledForUser = false,
    bouncerFullyShown = false,
    faceAndFpNotAuthenticated = false,
    faceAuthAllowed = true,
    faceDisabled = false,
    faceLockedOut = false,
    fpLockedOut = false,
    goingToSleep = false,
    keyguardAwake = false,
    keyguardGoingAway = false,
    listeningForFaceAssistant = false,
    occludingAppRequestingFaceAuth = false,
    primaryUser = false,
    scanningAllowedByStrongAuth = false,
    secureCameraLaunched = false,
    supportsDetect = true,
    switchingUser = false,
    udfpsBouncerShowing = false,
    udfpsFingerDown = false,
+195 −68

File changed.

Preview size limit exceeded, changes collapsed.