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