1 /* 2 * Copyright (C) 2020 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 android.server.biometrics; 18 19 import androidx.annotation.NonNull; 20 21 import com.android.server.biometrics.nano.BiometricSchedulerProto; 22 import com.android.server.biometrics.nano.BiometricsProto; 23 import com.android.server.biometrics.nano.SensorServiceStateProto; 24 import com.android.server.biometrics.nano.SensorStateProto; 25 import com.android.server.biometrics.nano.UserStateProto; 26 27 import com.google.common.primitives.Ints; 28 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Map; 32 33 /** 34 * The overall state for a list of sensors. This could be either: 35 * 36 * 1) A list of sensors from a single instance of a <Biometric>Service such as 37 * {@link com.android.server.biometrics.sensors.fingerprint.FingerprintService} or 38 * {@link com.android.server.biometrics.sensors.face.FaceService}, or 39 * 40 * 2) A list of sensors from multiple instances of <Biometric>Services. 41 * 42 * Note that a single service may provide multiple sensors. 43 */ 44 public class SensorStates { 45 46 @NonNull public final Map<Integer, SensorState> sensorStates; 47 48 public static class SchedulerState { 49 private final int mCurrentOperation; 50 private final int mTotalOperations; 51 @NonNull private final List<Integer> mRecentOperations; 52 parseFrom(@onNull BiometricSchedulerProto proto)53 public static SchedulerState parseFrom(@NonNull BiometricSchedulerProto proto) { 54 return new SchedulerState(proto.currentOperation, proto.totalOperations, 55 Ints.asList(proto.recentOperations)); 56 } 57 SchedulerState(int currentOperation, int totalOperations, @NonNull List<Integer> recentOperations)58 public SchedulerState(int currentOperation, int totalOperations, 59 @NonNull List<Integer> recentOperations) { 60 mCurrentOperation = currentOperation; 61 mTotalOperations = totalOperations; 62 mRecentOperations = recentOperations; 63 } 64 65 @NonNull getRecentOperations()66 public List<Integer> getRecentOperations() { 67 return mRecentOperations; 68 } 69 } 70 71 public static class SensorState { 72 private final SchedulerState mSchedulerState; 73 private final int mModality; 74 private final int[] mModalityFlags; 75 private final int mCurrentStrength; 76 @NonNull private final Map<Integer, UserState> mUserStates; 77 private final boolean mResetLockoutRequiresHardwareAuthToken; 78 private final boolean mResetLockoutRequiresChallenge; 79 SensorState(@onNull SchedulerState schedulerState, int modality, int[] modalityFlags, int currentStrength, @NonNull Map<Integer, UserState> userStates, boolean resetLockoutRequiresHardwareAuthToken, boolean resetLockoutRequiresChallenge)80 public SensorState(@NonNull SchedulerState schedulerState, 81 int modality, int[] modalityFlags, 82 int currentStrength, @NonNull Map<Integer, UserState> userStates, 83 boolean resetLockoutRequiresHardwareAuthToken, 84 boolean resetLockoutRequiresChallenge) { 85 mSchedulerState = schedulerState; 86 mModality = modality; 87 mModalityFlags = modalityFlags; 88 mCurrentStrength = currentStrength; 89 mUserStates = userStates; 90 mResetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken; 91 mResetLockoutRequiresChallenge = resetLockoutRequiresChallenge; 92 } 93 getSchedulerState()94 public SchedulerState getSchedulerState() { 95 return mSchedulerState; 96 } 97 isBusy()98 public boolean isBusy() { 99 return mSchedulerState.mCurrentOperation != BiometricsProto.CM_NONE; 100 } 101 getModality()102 public int getModality() { 103 return mModality; 104 } 105 hasModalityFlag(int flag)106 public boolean hasModalityFlag(int flag) { 107 for (int f : mModalityFlags) { 108 if (f == flag) { 109 return true; 110 } 111 } 112 113 return false; 114 } 115 getCurrentStrength()116 public int getCurrentStrength() { 117 return mCurrentStrength; 118 } 119 getUserStates()120 @NonNull public Map<Integer, UserState> getUserStates() { 121 return mUserStates; 122 } 123 isResetLockoutRequiresHardwareAuthToken()124 public boolean isResetLockoutRequiresHardwareAuthToken() { 125 return mResetLockoutRequiresHardwareAuthToken; 126 } 127 isResetLockoutRequiresChallenge()128 public boolean isResetLockoutRequiresChallenge() { 129 return mResetLockoutRequiresChallenge; 130 } 131 } 132 133 public static class UserState { 134 public final int numEnrolled; 135 UserState(int numEnrolled)136 public UserState(int numEnrolled) { 137 this.numEnrolled = numEnrolled; 138 } 139 } 140 141 @NonNull parseFrom(@onNull SensorServiceStateProto proto)142 public static SensorStates parseFrom(@NonNull SensorServiceStateProto proto) { 143 final Map<Integer, SensorState> sensorStates = new HashMap<>(); 144 145 for (SensorStateProto sensorStateProto : proto.sensorStates) { 146 final Map<Integer, UserState> userStates = new HashMap<>(); 147 for (UserStateProto userStateProto : sensorStateProto.userStates) { 148 userStates.put(userStateProto.userId, new UserState(userStateProto.numEnrolled)); 149 } 150 151 final SchedulerState schedulerState = 152 SchedulerState.parseFrom(sensorStateProto.scheduler); 153 final SensorState sensorState = new SensorState(schedulerState, 154 sensorStateProto.modality, sensorStateProto.modalityFlags, 155 sensorStateProto.currentStrength, userStates, 156 sensorStateProto.resetLockoutRequiresHardwareAuthToken, 157 sensorStateProto.resetLockoutRequiresChallenge); 158 sensorStates.put(sensorStateProto.sensorId, sensorState); 159 } 160 161 return new SensorStates(sensorStates); 162 } 163 164 /** 165 * Combines multiple {@link SensorStates} into a single instance. 166 */ 167 @NonNull merge(@onNull List<SensorStates> sensorServiceStates)168 public static SensorStates merge(@NonNull List<SensorStates> sensorServiceStates) { 169 final Map<Integer, SensorState> sensorStates = new HashMap<>(); 170 171 for (SensorStates sensorServiceState : sensorServiceStates) { 172 for (Integer sensorId : sensorServiceState.sensorStates.keySet()) { 173 if (sensorStates.containsKey(sensorId)) { 174 throw new IllegalStateException("Duplicate sensorId found: " + sensorId); 175 } 176 sensorStates.put(sensorId, sensorServiceState.sensorStates.get(sensorId)); 177 } 178 } 179 180 return new SensorStates(sensorStates); 181 } 182 areAllSensorsIdle()183 public boolean areAllSensorsIdle() { 184 for (SensorState state : sensorStates.values()) { 185 if (state.isBusy()) { 186 return false; 187 } 188 } 189 190 return true; 191 } 192 containsModality(int modality)193 public boolean containsModality(int modality) { 194 for (SensorState state : sensorStates.values()) { 195 if (state.getModality() == modality) { 196 return true; 197 } 198 } 199 200 return false; 201 } 202 containsModalityFlag(int flag)203 public boolean containsModalityFlag(int flag) { 204 for (SensorState state : sensorStates.values()) { 205 if (state.hasModalityFlag(flag)) { 206 return true; 207 } 208 } 209 210 return false; 211 } 212 SensorStates(@onNull Map<Integer, SensorState> sensorStates)213 private SensorStates(@NonNull Map<Integer, SensorState> sensorStates) { 214 this.sensorStates = sensorStates; 215 } 216 217 @Override toString()218 public String toString() { 219 final StringBuilder sb = new StringBuilder(); 220 221 for (Integer sensorId : sensorStates.keySet()) { 222 sb.append("{SensorId: ").append(sensorId); 223 sb.append(", Operation: ").append(sensorStates.get(sensorId) 224 .getSchedulerState().mCurrentOperation); 225 226 final Map<Integer, UserState> userStates = sensorStates.get(sensorId).getUserStates(); 227 for (Integer userId : userStates.keySet()) { 228 sb.append(", UserId: ").append(userId); 229 sb.append(", NumEnrolled: ").append(userStates.get(userId).numEnrolled); 230 } 231 sb.append("} "); 232 } 233 return sb.toString(); 234 } 235 } 236