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 com.android.systemui.user.domain.interactor.SelectedUserInteractor 33 import java.io.PrintWriter 34 import javax.inject.Inject 35 36 /** 37 * Logs events when primary authentication requirements change. Primary authentication is considered 38 * authentication using pin/pattern/password input. 39 * 40 * See [PrimaryAuthRequiredEvent] for all the events and their descriptions. 41 */ 42 @SysUISingleton 43 class KeyguardBiometricLockoutLogger @Inject constructor( 44 private val uiEventLogger: UiEventLogger, 45 private val keyguardUpdateMonitor: KeyguardUpdateMonitor, 46 private val sessionTracker: SessionTracker, 47 private val selectedUserInteractor: SelectedUserInteractor 48 ) : CoreStartable { 49 private var fingerprintLockedOut = false 50 private var faceLockedOut = false 51 private var encryptedOrLockdown = false 52 private var unattendedUpdate = false 53 private var timeout = false 54 startnull55 override fun start() { 56 mKeyguardUpdateMonitorCallback.onStrongAuthStateChanged( 57 selectedUserInteractor.getSelectedUserId()) 58 keyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback) 59 } 60 61 private val mKeyguardUpdateMonitorCallback: KeyguardUpdateMonitorCallback = 62 object : KeyguardUpdateMonitorCallback() { onLockedOutStateChangednull63 override fun onLockedOutStateChanged(biometricSourceType: BiometricSourceType) { 64 if (biometricSourceType == BiometricSourceType.FINGERPRINT) { 65 val lockedOut = keyguardUpdateMonitor.isFingerprintLockedOut 66 if (lockedOut && !fingerprintLockedOut) { 67 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT) 68 } else if (!lockedOut && fingerprintLockedOut) { 69 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT_RESET) 70 } 71 fingerprintLockedOut = lockedOut 72 } else if (biometricSourceType == BiometricSourceType.FACE) { 73 val lockedOut = keyguardUpdateMonitor.isFaceLockedOut 74 if (lockedOut && !faceLockedOut) { 75 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT) 76 } else if (!lockedOut && faceLockedOut) { 77 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT_RESET) 78 } 79 faceLockedOut = lockedOut 80 } 81 } 82 onStrongAuthStateChangednull83 override fun onStrongAuthStateChanged(userId: Int) { 84 if (userId != selectedUserInteractor.getSelectedUserId()) { 85 return 86 } 87 val strongAuthFlags = keyguardUpdateMonitor.strongAuthTracker 88 .getStrongAuthForUser(userId) 89 90 val newEncryptedOrLockdown = keyguardUpdateMonitor.isEncryptedOrLockdown(userId) 91 if (newEncryptedOrLockdown && !encryptedOrLockdown) { 92 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_ENCRYPTED_OR_LOCKDOWN) 93 } 94 encryptedOrLockdown = newEncryptedOrLockdown 95 96 val newUnattendedUpdate = isUnattendedUpdate(strongAuthFlags) 97 if (newUnattendedUpdate && !unattendedUpdate) { 98 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_UNATTENDED_UPDATE) 99 } 100 unattendedUpdate = newUnattendedUpdate 101 102 val newTimeout = isStrongAuthTimeout(strongAuthFlags) 103 if (newTimeout && !timeout) { 104 log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_TIMEOUT) 105 } 106 timeout = newTimeout 107 } 108 } 109 isUnattendedUpdatenull110 private fun isUnattendedUpdate( 111 @LockPatternUtils.StrongAuthTracker.StrongAuthFlags flags: Int 112 ) = containsFlag(flags, STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE) 113 114 private fun isStrongAuthTimeout( 115 @LockPatternUtils.StrongAuthTracker.StrongAuthFlags flags: Int 116 ) = containsFlag(flags, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) || 117 containsFlag(flags, STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT) 118 119 private fun log(event: PrimaryAuthRequiredEvent) = 120 uiEventLogger.log(event, sessionTracker.getSessionId(SESSION_KEYGUARD)) 121 122 override fun dump(pw: PrintWriter, args: Array<String>) { 123 pw.println(" mFingerprintLockedOut=$fingerprintLockedOut") 124 pw.println(" mFaceLockedOut=$faceLockedOut") 125 pw.println(" mIsEncryptedOrLockdown=$encryptedOrLockdown") 126 pw.println(" mIsUnattendedUpdate=$unattendedUpdate") 127 pw.println(" mIsTimeout=$timeout") 128 } 129 130 /** 131 * Events pertaining to whether primary authentication (pin/pattern/password input) is required 132 * for device entry. 133 */ 134 @VisibleForTesting 135 enum class PrimaryAuthRequiredEvent(private val mId: Int) : UiEventLogger.UiEventEnum { 136 @UiEvent(doc = "Fingerprint cannot be used to authenticate for device entry. This" + 137 "can persist until the next primary auth or may timeout.") 138 PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT(924), 139 140 @UiEvent(doc = "Fingerprint can be used to authenticate for device entry.") 141 PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT_RESET(925), 142 143 @UiEvent(doc = "Face cannot be used to authenticate for device entry.") 144 PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT(926), 145 146 @UiEvent(doc = "Face can be used to authenticate for device entry.") 147 PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT_RESET(927), 148 149 @UiEvent(doc = "Device is encrypted (ie: after reboot) or device is locked down by DPM " + 150 "or a manual user lockdown.") 151 PRIMARY_AUTH_REQUIRED_ENCRYPTED_OR_LOCKDOWN(928), 152 153 @UiEvent(doc = "Primary authentication is required because it hasn't been used for a " + 154 "time required by a device admin or because primary auth hasn't been used for a " + 155 "time after a non-strong biometric (weak or convenience) is used to unlock the " + 156 "device.") 157 PRIMARY_AUTH_REQUIRED_TIMEOUT(929), 158 159 @UiEvent(doc = "Strong authentication is required to prepare for unattended upgrade.") 160 PRIMARY_AUTH_REQUIRED_UNATTENDED_UPDATE(931); 161 getIdnull162 override fun getId(): Int { 163 return mId 164 } 165 } 166 167 companion object { containsFlagnull168 private fun containsFlag(strongAuthFlags: Int, flagCheck: Int): Boolean { 169 return strongAuthFlags and flagCheck != 0 170 } 171 } 172 } 173