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.server.biometrics.sensors;
18 
19 import android.hardware.biometrics.BiometricManager.Authenticators;
20 import android.util.ArrayMap;
21 
22 import java.util.Collections;
23 import java.util.Map;
24 import java.util.function.IntFunction;
25 
26 /**
27  * A class that takes in a series of authentication attempts (successes, failures, lockouts)
28  * across different biometric strengths (convenience, weak, strong) and returns a single AuthResult.
29  *
30  * The AuthResult will be the strongest biometric operation that occurred amongst all reported
31  * operations, and if multiple such operations exist, it will favor a successful authentication.
32  */
33 class AuthResultCoordinator {
34 
35     /**
36      * Indicates no change has occurred with this authenticator.
37      */
38     static final int AUTHENTICATOR_DEFAULT = 0;
39     /**
40      * Indicated this authenticator has received a permanent lockout.
41      */
42     static final int AUTHENTICATOR_PERMANENT_LOCKED = 1 << 0;
43     /**
44      * Indicates this authenticator has received a timed unlock.
45      */
46     static final int AUTHENTICATOR_TIMED_LOCKED = 1 << 1;
47     /**
48      * Indicates this authenticator has received a successful unlock.
49      */
50     static final int AUTHENTICATOR_UNLOCKED = 1 << 2;
51     private static final String TAG = "AuthResultCoordinator";
52     private final Map<Integer, Integer> mAuthenticatorState;
53 
AuthResultCoordinator()54     AuthResultCoordinator() {
55         mAuthenticatorState = new ArrayMap<>();
56         mAuthenticatorState.put(Authenticators.BIOMETRIC_STRONG, AUTHENTICATOR_DEFAULT);
57         mAuthenticatorState.put(Authenticators.BIOMETRIC_WEAK, AUTHENTICATOR_DEFAULT);
58         mAuthenticatorState.put(Authenticators.BIOMETRIC_CONVENIENCE, AUTHENTICATOR_DEFAULT);
59     }
60 
updateState(@uthenticators.Types int strength, IntFunction<Integer> mapper)61     private void updateState(@Authenticators.Types int strength, IntFunction<Integer> mapper) {
62         switch (strength) {
63             case Authenticators.BIOMETRIC_STRONG:
64                 mAuthenticatorState.put(Authenticators.BIOMETRIC_STRONG,
65                         mapper.apply(mAuthenticatorState.get(Authenticators.BIOMETRIC_STRONG)));
66                 // fall through
67             case Authenticators.BIOMETRIC_WEAK:
68                 mAuthenticatorState.put(Authenticators.BIOMETRIC_WEAK,
69                         mapper.apply(mAuthenticatorState.get(Authenticators.BIOMETRIC_WEAK)));
70                 // fall through
71             case Authenticators.BIOMETRIC_CONVENIENCE:
72                 mAuthenticatorState.put(Authenticators.BIOMETRIC_CONVENIENCE,
73                         mapper.apply(
74                                 mAuthenticatorState.get(Authenticators.BIOMETRIC_CONVENIENCE)));
75         }
76     }
77 
78     /**
79      * Adds auth success for a given strength to the current operation list.
80      */
authenticatedFor(@uthenticators.Types int strength)81     void authenticatedFor(@Authenticators.Types int strength) {
82         // Only strong unlocks matter.
83         if (strength == Authenticators.BIOMETRIC_STRONG) {
84             updateState(strength, (old) -> AUTHENTICATOR_UNLOCKED | old);
85         }
86     }
87 
88     /**
89      * Adds a lock out of a given strength to the current operation list.
90      */
lockedOutFor(@uthenticators.Types int strength)91     void lockedOutFor(@Authenticators.Types int strength) {
92         updateState(strength, (old) -> AUTHENTICATOR_PERMANENT_LOCKED | old);
93     }
94 
95     /**
96      * Adds a timed lock out of a given strength to the current operation list.
97      */
lockOutTimed(@uthenticators.Types int strength)98     void lockOutTimed(@Authenticators.Types int strength) {
99         updateState(strength, (old) -> AUTHENTICATOR_TIMED_LOCKED | old);
100     }
101 
102     /**
103      * Returns the current authenticator state. Each authenticator will have
104      * the associated operations that were performed on them(DEFAULT, LOCKED, UNLOCKED).
105      */
getResult()106     final Map<Integer, Integer> getResult() {
107         return Collections.unmodifiableMap(mAuthenticatorState);
108     }
109 }
110