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

Commit 1b31769f authored by Beverly Tai's avatar Beverly Tai Committed by Android (Google) Code Review
Browse files

Merge "Log biometric lockout events"

parents 15417808 31354318
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -294,6 +294,7 @@
    <string-array name="config_systemUIServiceComponents" translatable="false">
    <string-array name="config_systemUIServiceComponents" translatable="false">
        <item>com.android.systemui.util.NotificationChannels</item>
        <item>com.android.systemui.util.NotificationChannels</item>
        <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
        <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
        <item>com.android.keyguard.KeyguardBiometricLockoutLogger</item>
        <item>com.android.systemui.recents.Recents</item>
        <item>com.android.systemui.recents.Recents</item>
        <item>com.android.systemui.volume.VolumeUI</item>
        <item>com.android.systemui.volume.VolumeUI</item>
        <item>com.android.systemui.statusbar.phone.StatusBar</item>
        <item>com.android.systemui.statusbar.phone.StatusBar</item>
+176 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.keyguard

import android.content.Context
import android.hardware.biometrics.BiometricSourceType
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE
import com.android.keyguard.KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import java.io.FileDescriptor
import java.io.PrintWriter
import javax.inject.Inject

/**
 * Logs events when primary authentication requirements change. Primary authentication is considered
 * authentication using pin/pattern/password input.
 *
 * See [PrimaryAuthRequiredEvent] for all the events and their descriptions.
 */
@SysUISingleton
class KeyguardBiometricLockoutLogger @Inject constructor(
    context: Context?,
    private val uiEventLogger: UiEventLogger,
    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
    private val dumpManager: DumpManager
) : CoreStartable(context) {
    private var fingerprintLockedOut = false
    private var faceLockedOut = false
    private var encryptedOrLockdown = false
    private var unattendedUpdate = false
    private var timeout = false

    override fun start() {
        dumpManager.registerDumpable(this)
        mKeyguardUpdateMonitorCallback.onStrongAuthStateChanged(
                KeyguardUpdateMonitor.getCurrentUser())
        keyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback)
    }

    private val mKeyguardUpdateMonitorCallback: KeyguardUpdateMonitorCallback =
            object : KeyguardUpdateMonitorCallback() {
        override fun onLockedOutStateChanged(biometricSourceType: BiometricSourceType) {
            if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
                val lockedOut = keyguardUpdateMonitor.isFingerprintLockedOut
                if (lockedOut && !fingerprintLockedOut) {
                    uiEventLogger.log(
                            PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT)
                } else if (!lockedOut && fingerprintLockedOut) {
                    uiEventLogger.log(
                            PrimaryAuthRequiredEvent
                                    .PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT_RESET)
                }
                fingerprintLockedOut = lockedOut
            } else if (biometricSourceType == BiometricSourceType.FACE) {
                val lockedOut = keyguardUpdateMonitor.isFaceLockedOut
                if (lockedOut && !faceLockedOut) {
                    uiEventLogger.log(
                            PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT)
                } else if (!lockedOut && faceLockedOut) {
                    uiEventLogger.log(
                            PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT_RESET)
                }
                faceLockedOut = lockedOut
            }
        }

        override fun onStrongAuthStateChanged(userId: Int) {
            if (userId != KeyguardUpdateMonitor.getCurrentUser()) {
                return
            }
            val strongAuthFlags = keyguardUpdateMonitor.strongAuthTracker
                    .getStrongAuthForUser(userId)

            val newEncryptedOrLockdown = keyguardUpdateMonitor.isEncryptedOrLockdown(userId)
            if (newEncryptedOrLockdown && !encryptedOrLockdown) {
                uiEventLogger.log(
                        PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_ENCRYPTED_OR_LOCKDOWN)
            }
            encryptedOrLockdown = newEncryptedOrLockdown

            val newUnattendedUpdate = isUnattendedUpdate(strongAuthFlags)
            if (newUnattendedUpdate && !unattendedUpdate) {
                uiEventLogger.log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_UNATTENDED_UPDATE)
            }
            unattendedUpdate = newUnattendedUpdate

            val newTimeout = isStrongAuthTimeout(strongAuthFlags)
            if (newTimeout && !timeout) {
                uiEventLogger.log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_TIMEOUT)
            }
            timeout = newTimeout
        }
    }

    private fun isUnattendedUpdate(
        @LockPatternUtils.StrongAuthTracker.StrongAuthFlags flags: Int
    ) = containsFlag(flags, STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE)

    private fun isStrongAuthTimeout(
        @LockPatternUtils.StrongAuthTracker.StrongAuthFlags flags: Int
    ) = containsFlag(flags, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) ||
            containsFlag(flags, STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT)

    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
        pw.println("  mFingerprintLockedOut=$fingerprintLockedOut")
        pw.println("  mFaceLockedOut=$faceLockedOut")
        pw.println("  mIsEncryptedOrLockdown=$encryptedOrLockdown")
        pw.println("  mIsUnattendedUpdate=$unattendedUpdate")
        pw.println("  mIsTimeout=$timeout")
    }

    /**
     * Events pertaining to whether primary authentication (pin/pattern/password input) is required
     * for device entry.
     */
    @VisibleForTesting
    enum class PrimaryAuthRequiredEvent(private val mId: Int) : UiEventLogger.UiEventEnum {
        @UiEvent(doc = "Fingerprint cannot be used to authenticate for device entry. This" +
                "can persist until the next primary auth or may timeout.")
        PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT(924),

        @UiEvent(doc = "Fingerprint can be used to authenticate for device entry.")
        PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT_RESET(925),

        @UiEvent(doc = "Face cannot be used to authenticate for device entry.")
        PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT(926),

        @UiEvent(doc = "Face can be used to authenticate for device entry.")
        PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT_RESET(927),

        @UiEvent(doc = "Device is encrypted (ie: after reboot) or device is locked down by DPM " +
                "or a manual user lockdown.")
        PRIMARY_AUTH_REQUIRED_ENCRYPTED_OR_LOCKDOWN(928),

        @UiEvent(doc = "Primary authentication is required because it hasn't been used for a " +
                "time required by a device admin or because primary auth hasn't been used for a " +
                "time after a non-strong biometric (weak or convenience) is used to unlock the " +
                "device.")
        PRIMARY_AUTH_REQUIRED_TIMEOUT(929),

        @UiEvent(doc = "Strong authentication is required to prepare for unattended upgrade.")
        PRIMARY_AUTH_REQUIRED_UNATTENDED_UPDATE(931);

        override fun getId(): Int {
            return mId
        }
    }

    companion object {
        private fun containsFlag(strongAuthFlags: Int, flagCheck: Int): Boolean {
            return strongAuthFlags and flagCheck != 0
        }
    }
}
 No newline at end of file
+9 −4
Original line number Original line Diff line number Diff line
@@ -183,7 +183,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    private static final int MSG_USER_STOPPED = 340;
    private static final int MSG_USER_STOPPED = 340;
    private static final int MSG_USER_REMOVED = 341;
    private static final int MSG_USER_REMOVED = 341;
    private static final int MSG_KEYGUARD_GOING_AWAY = 342;
    private static final int MSG_KEYGUARD_GOING_AWAY = 342;
    private static final int MSG_LOCK_SCREEN_MODE = 343;
    private static final int MSG_TIME_FORMAT_UPDATE = 344;
    private static final int MSG_TIME_FORMAT_UPDATE = 344;
    private static final int MSG_REQUIRE_NFC_UNLOCK = 345;
    private static final int MSG_REQUIRE_NFC_UNLOCK = 345;


@@ -221,7 +220,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    private static final int BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED = -1;
    private static final int BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED = -1;
    public static final int BIOMETRIC_HELP_FACE_NOT_RECOGNIZED = -2;
    public static final int BIOMETRIC_HELP_FACE_NOT_RECOGNIZED = -2;


    private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
    /**
    /**
     * If no cancel signal has been received after this amount of time, set the biometric running
     * If no cancel signal has been received after this amount of time, set the biometric running
     * state to stopped to allow Keyguard to retry authentication.
     * state to stopped to allow Keyguard to retry authentication.
@@ -231,7 +229,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
    private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
            "com.android.settings", "com.android.settings.FallbackHome");
            "com.android.settings", "com.android.settings.FallbackHome");



    /**
    /**
     * If true, the system is in the half-boot-to-decryption-screen state.
     * If true, the system is in the half-boot-to-decryption-screen state.
     * Prudently disable lockscreen.
     * Prudently disable lockscreen.
@@ -1250,7 +1247,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
                STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
    }
    }


    private boolean isEncryptedOrLockdown(int userId) {
    /**
     * Returns true if primary authentication is required for the given user due to lockdown
     * or encryption after reboot.
     */
    public boolean isEncryptedOrLockdown(int userId) {
        final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(userId);
        final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(userId);
        final boolean isLockDown =
        final boolean isLockDown =
                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
@@ -2514,6 +2515,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        return mFingerprintLockedOut || mFingerprintLockedOutPermanent;
        return mFingerprintLockedOut || mFingerprintLockedOutPermanent;
    }
    }


    public boolean isFaceLockedOut() {
        return mFaceLockedOutPermanent;
    }

    /**
    /**
     * If biometrics hardware is available, not disabled, and user has enrolled templates.
     * If biometrics hardware is available, not disabled, and user has enrolled templates.
     * This does NOT check if the device is encrypted or in lockdown.
     * This does NOT check if the device is encrypted or in lockdown.
+8 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.systemui.dagger;
package com.android.systemui.dagger;


import com.android.keyguard.KeyguardBiometricLockoutLogger;
import com.android.systemui.CoreStartable;
import com.android.systemui.CoreStartable;
import com.android.systemui.LatencyTester;
import com.android.systemui.LatencyTester;
import com.android.systemui.ScreenDecorations;
import com.android.systemui.ScreenDecorations;
@@ -90,6 +91,13 @@ public abstract class SystemUIBinder {
    @ClassKey(KeyguardViewMediator.class)
    @ClassKey(KeyguardViewMediator.class)
    public abstract CoreStartable bindKeyguardViewMediator(KeyguardViewMediator sysui);
    public abstract CoreStartable bindKeyguardViewMediator(KeyguardViewMediator sysui);


    /** Inject into KeyguardBiometricLockoutLogger. */
    @Binds
    @IntoMap
    @ClassKey(KeyguardBiometricLockoutLogger.class)
    public abstract CoreStartable bindKeyguardBiometricLockoutLogger(
            KeyguardBiometricLockoutLogger sysui);

    /** Inject into LatencyTests. */
    /** Inject into LatencyTests. */
    @Binds
    @Binds
    @IntoMap
    @IntoMap
+1 −1
Original line number Original line Diff line number Diff line
@@ -11,7 +11,7 @@
 * distributed under the License is distributed on an "AS IS" BASIS,
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * See the License for the specific language governing permissions and
 * limitations under the License
 * limitations under the License.
 */
 */


package com.android.systemui.statusbar.phone;
package com.android.systemui.statusbar.phone;
Loading