1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.keyguard 18 19 import android.app.StatusBarManager.SESSION_KEYGUARD 20 import android.hardware.biometrics.BiometricSourceType 21 import com.android.internal.annotations.VisibleForTesting 22 import com.android.internal.logging.UiEvent 23 import com.android.internal.logging.UiEventLogger 24 import com.android.internal.widget.LockPatternUtils 25 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT 26 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT 27 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE 28 import com.android.keyguard.KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent 29 import com.android.systemui.CoreStartable 30 import com.android.systemui.dagger.SysUISingleton 31 import com.android.systemui.log.SessionTracker 32 import java.io.PrintWriter 33 import javax.inject.Inject 34 35 /** 36 * Logs events when primary authentication requirements change. Primary authentication is considered 37 * authentication using pin/pattern/password input. 38 * 39 * See [PrimaryAuthRequiredEvent] for all the events and their descriptions. 40 */ 41 @SysUISingleton 42 class KeyguardBiometricLockoutLogger @Inject constructor( 43 private val uiEventLogger: UiEventLogger, 44 private val keyguardUpdateMonitor: KeyguardUpdateMonitor, 45 private val sessionTracker: SessionTracker 46 ) : CoreStartable { 47 private var fingerprintLockedOut = false 48 private var faceLockedOut = false 49 private var encryptedOrLockdown = false 50 private var unattendedUpdate = false 51 private var timeout = false 52 53 override fun start() { 54 mKeyguardUpdateMonitorCallback.onStrongAuthStateChanged( 55 KeyguardUpdateMonitor.getCurrentUser()) 56 keyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback) 57 } 58 59 private val mKeyguardUpdateMonitorCallback: KeyguardUpdateMonitorCallback = 60 object : KeyguardUpdateMonitorCallback() { 61 override fun onLockedOutStateChanged(biometricSourceType: BiometricSourceType) { 62 if (biometricSourceType == BiometricSourceType.FINGERPRINT) { 63 val lockedOut = keyguardUpdateMonitor.isFingerprintLockedOut 64 if (lockedOut && !fingerprintLockedOut) { 65 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT) 66 } else if (!lockedOut && fingerprintLockedOut) { 67 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT_RESET) 68 } 69 fingerprintLockedOut = lockedOut 70 } else if (biometricSourceType == BiometricSourceType.FACE) { 71 val lockedOut = keyguardUpdateMonitor.isFaceLockedOut 72 if (lockedOut && !faceLockedOut) { 73 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT) 74 } else if (!lockedOut && faceLockedOut) { 75 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT_RESET) 76 } 77 faceLockedOut = lockedOut 78 } 79 } 80 81 override fun onStrongAuthStateChanged(userId: Int) { 82 if (userId != KeyguardUpdateMonitor.getCurrentUser()) { 83 return 84 } 85 val strongAuthFlags = keyguardUpdateMonitor.strongAuthTracker 86 .getStrongAuthForUser(userId) 87 88 val newEncryptedOrLockdown = keyguardUpdateMonitor.isEncryptedOrLockdown(userId) 89 if (newEncryptedOrLockdown && !encryptedOrLockdown) { 90 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_ENCRYPTED_OR_LOCKDOWN) 91 } 92 encryptedOrLockdown = newEncryptedOrLockdown 93 94 val newUnattendedUpdate = isUnattendedUpdate(strongAuthFlags) 95 if (newUnattendedUpdate && !unattendedUpdate) { 96 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_UNATTENDED_UPDATE) 97 } 98 unattendedUpdate = newUnattendedUpdate 99 100 val newTimeout = isStrongAuthTimeout(strongAuthFlags) 101 if (newTimeout && !timeout) { 102 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_TIMEOUT) 103 } 104 timeout = newTimeout 105 } 106 } 107 108 private fun isUnattendedUpdate( 109 @LockPatternUtils.StrongAuthTracker.StrongAuthFlags flags: Int 110 ) = containsFlag(flags, STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE) 111 112 private fun isStrongAuthTimeout( 113 @LockPatternUtils.StrongAuthTracker.StrongAuthFlags flags: Int 114 ) = containsFlag(flags, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) || 115 containsFlag(flags, STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT) 116 117 private fun log(event: PrimaryAuthRequiredEvent) = 118 uiEventLogger.log(event, sessionTracker.getSessionId(SESSION_KEYGUARD)) 119 120 override fun dump(pw: PrintWriter, args: Array<String>) { 121 pw.println(" mFingerprintLockedOut=$fingerprintLockedOut") 122 pw.println(" mFaceLockedOut=$faceLockedOut") 123 pw.println(" mIsEncryptedOrLockdown=$encryptedOrLockdown") 124 pw.println(" mIsUnattendedUpdate=$unattendedUpdate") 125 pw.println(" mIsTimeout=$timeout") 126 } 127 128 /** 129 * Events pertaining to whether primary authentication (pin/pattern/password input) is required 130 * for device entry. 131 */ 132 @VisibleForTesting 133 enum class PrimaryAuthRequiredEvent(private val mId: Int) : UiEventLogger.UiEventEnum { 134 @UiEvent(doc = "Fingerprint cannot be used to authenticate for device entry. This" + 135 "can persist until the next primary auth or may timeout.") 136 PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT(924), 137 138 @UiEvent(doc = "Fingerprint can be used to authenticate for device entry.") 139 PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT_RESET(925), 140 141 @UiEvent(doc = "Face cannot be used to authenticate for device entry.") 142 PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT(926), 143 144 @UiEvent(doc = "Face can be used to authenticate for device entry.") 145 PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT_RESET(927), 146 147 @UiEvent(doc = "Device is encrypted (ie: after reboot) or device is locked down by DPM " + 148 "or a manual user lockdown.") 149 PRIMARY_AUTH_REQUIRED_ENCRYPTED_OR_LOCKDOWN(928), 150 151 @UiEvent(doc = "Primary authentication is required because it hasn't been used for a " + 152 "time required by a device admin or because primary auth hasn't been used for a " + 153 "time after a non-strong biometric (weak or convenience) is used to unlock the " + 154 "device.") 155 PRIMARY_AUTH_REQUIRED_TIMEOUT(929), 156 157 @UiEvent(doc = "Strong authentication is required to prepare for unattended upgrade.") 158 PRIMARY_AUTH_REQUIRED_UNATTENDED_UPDATE(931); 159 160 override fun getId(): Int { 161 return mId 162 } 163 } 164 165 companion object { 166 private fun containsFlag(strongAuthFlags: Int, flagCheck: Int): Boolean { 167 return strongAuthFlags and flagCheck != 0 168 } 169 } 170 } 171