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.log; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.hardware.biometrics.BiometricsProtoEnums; 22 import android.hardware.biometrics.IBiometricContextListener; 23 import android.hardware.biometrics.common.AuthenticateReason; 24 import android.hardware.biometrics.common.OperationContext; 25 import android.hardware.biometrics.common.OperationReason; 26 import android.hardware.biometrics.common.WakeReason; 27 import android.util.Slog; 28 import android.view.Surface; 29 30 import com.android.internal.annotations.VisibleForTesting; 31 import com.android.internal.util.FrameworkStatsLog; 32 33 import java.util.stream.Stream; 34 35 /** 36 * Wrapper for {@link FrameworkStatsLog} to isolate the testable parts. 37 */ 38 public class BiometricFrameworkStatsLogger { 39 40 private static final String TAG = "BiometricFrameworkStatsLogger"; 41 42 private static final BiometricFrameworkStatsLogger sInstance = 43 new BiometricFrameworkStatsLogger(); 44 BiometricFrameworkStatsLogger()45 private BiometricFrameworkStatsLogger() {} 46 47 /** Shared instance. */ getInstance()48 public static BiometricFrameworkStatsLogger getInstance() { 49 return sInstance; 50 } 51 52 /** {@see FrameworkStatsLog.BIOMETRIC_ACQUIRED}. */ acquired(OperationContextExt operationContext, int statsModality, int statsAction, int statsClient, boolean isDebug, int acquiredInfo, int vendorCode, int targetUserId)53 public void acquired(OperationContextExt operationContext, 54 int statsModality, int statsAction, int statsClient, boolean isDebug, 55 int acquiredInfo, int vendorCode, int targetUserId) { 56 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ACQUIRED, 57 statsModality, 58 targetUserId, 59 operationContext.isCrypto(), 60 statsAction, 61 statsClient, 62 acquiredInfo, 63 vendorCode, 64 isDebug, 65 -1 /* sensorId */, 66 operationContext.getId(), 67 sessionType(operationContext.getReason()), 68 operationContext.isAod(), 69 operationContext.isDisplayOn(), 70 operationContext.getDockState(), 71 orientationType(operationContext.getOrientation()), 72 foldType(operationContext.getFoldState()), 73 operationContext.getOrderAndIncrement(), 74 toProtoWakeReason(operationContext)); 75 } 76 77 /** {@see FrameworkStatsLog.BIOMETRIC_AUTHENTICATED}. */ authenticate(OperationContextExt operationContext, int statsModality, int statsAction, int statsClient, boolean isDebug, long latency, int authState, boolean requireConfirmation, int targetUserId, float ambientLightLux)78 public void authenticate(OperationContextExt operationContext, 79 int statsModality, int statsAction, int statsClient, boolean isDebug, long latency, 80 int authState, boolean requireConfirmation, int targetUserId, float ambientLightLux) { 81 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED, 82 statsModality, 83 targetUserId, 84 operationContext.isCrypto(), 85 statsClient, 86 requireConfirmation, 87 authState, 88 sanitizeLatency(latency), 89 isDebug, 90 -1 /* sensorId */, 91 ambientLightLux, 92 operationContext.getId(), 93 sessionType(operationContext.getReason()), 94 operationContext.isAod(), 95 operationContext.isDisplayOn(), 96 operationContext.getDockState(), 97 orientationType(operationContext.getOrientation()), 98 foldType(operationContext.getFoldState()), 99 operationContext.getOrderAndIncrement(), 100 toProtoWakeReason(operationContext), 101 toProtoWakeReasonDetails(operationContext)); 102 } 103 104 /** {@see FrameworkStatsLog.BIOMETRIC_AUTHENTICATED}. */ authenticate(OperationContextExt operationContext, int statsModality, int statsAction, int statsClient, boolean isDebug, long latency, int authState, boolean requireConfirmation, int targetUserId, ALSProbe alsProbe)105 public void authenticate(OperationContextExt operationContext, 106 int statsModality, int statsAction, int statsClient, boolean isDebug, long latency, 107 int authState, boolean requireConfirmation, int targetUserId, ALSProbe alsProbe) { 108 alsProbe.awaitNextLux((ambientLightLux) -> { 109 authenticate(operationContext, statsModality, statsAction, statsClient, isDebug, 110 latency, authState, requireConfirmation, targetUserId, ambientLightLux); 111 }, null /* handler */); 112 } 113 114 /** {@see FrameworkStatsLog.BIOMETRIC_ENROLLED}. */ enroll(int statsModality, int statsAction, int statsClient, int targetUserId, long latency, boolean enrollSuccessful, float ambientLightLux)115 public void enroll(int statsModality, int statsAction, int statsClient, 116 int targetUserId, long latency, boolean enrollSuccessful, float ambientLightLux) { 117 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ENROLLED, 118 statsModality, 119 targetUserId, 120 sanitizeLatency(latency), 121 enrollSuccessful, 122 -1, /* sensorId */ 123 ambientLightLux); 124 } 125 126 /** {@see FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED}. */ error(OperationContextExt operationContext, int statsModality, int statsAction, int statsClient, boolean isDebug, long latency, int error, int vendorCode, int targetUserId)127 public void error(OperationContextExt operationContext, 128 int statsModality, int statsAction, int statsClient, boolean isDebug, long latency, 129 int error, int vendorCode, int targetUserId) { 130 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED, 131 statsModality, 132 targetUserId, 133 operationContext.isCrypto(), 134 statsAction, 135 statsClient, 136 error, 137 vendorCode, 138 isDebug, 139 sanitizeLatency(latency), 140 -1 /* sensorId */, 141 operationContext.getId(), 142 sessionType(operationContext.getReason()), 143 operationContext.isAod(), 144 operationContext.isDisplayOn(), 145 operationContext.getDockState(), 146 orientationType(operationContext.getOrientation()), 147 foldType(operationContext.getFoldState()), 148 operationContext.getOrderAndIncrement(), 149 toProtoWakeReason(operationContext), 150 toProtoWakeReasonDetails(operationContext)); 151 } 152 153 @VisibleForTesting toProtoWakeReasonDetails(@onNull OperationContextExt operationContext)154 static int[] toProtoWakeReasonDetails(@NonNull OperationContextExt operationContext) { 155 final OperationContext ctx = operationContext.toAidlContext(); 156 return Stream.of(toProtoWakeReasonDetails(ctx.authenticateReason)) 157 .mapToInt(i -> i) 158 .filter(i -> i != BiometricsProtoEnums.DETAILS_UNKNOWN) 159 .toArray(); 160 } 161 162 @VisibleForTesting toProtoWakeReason(@onNull OperationContextExt operationContext)163 static int toProtoWakeReason(@NonNull OperationContextExt operationContext) { 164 @WakeReason final int reason = operationContext.getWakeReason(); 165 switch (reason) { 166 case WakeReason.POWER_BUTTON: 167 return BiometricsProtoEnums.WAKE_REASON_POWER_BUTTON; 168 case WakeReason.GESTURE: 169 return BiometricsProtoEnums.WAKE_REASON_GESTURE; 170 case WakeReason.WAKE_KEY: 171 return BiometricsProtoEnums.WAKE_REASON_WAKE_KEY; 172 case WakeReason.WAKE_MOTION: 173 return BiometricsProtoEnums.WAKE_REASON_WAKE_MOTION; 174 case WakeReason.LID: 175 return BiometricsProtoEnums.WAKE_REASON_LID; 176 case WakeReason.DISPLAY_GROUP_ADDED: 177 return BiometricsProtoEnums.WAKE_REASON_DISPLAY_GROUP_ADDED; 178 case WakeReason.TAP: 179 return BiometricsProtoEnums.WAKE_REASON_TAP; 180 case WakeReason.LIFT: 181 return BiometricsProtoEnums.WAKE_REASON_LIFT; 182 case WakeReason.BIOMETRIC: 183 return BiometricsProtoEnums.WAKE_REASON_BIOMETRIC; 184 default: 185 return BiometricsProtoEnums.WAKE_REASON_UNKNOWN; 186 } 187 } 188 toProtoWakeReasonDetails(@ullable AuthenticateReason reason)189 private static int toProtoWakeReasonDetails(@Nullable AuthenticateReason reason) { 190 if (reason != null) { 191 switch (reason.getTag()) { 192 case AuthenticateReason.faceAuthenticateReason: 193 return toProtoWakeReasonDetailsFromFace(reason.getFaceAuthenticateReason()); 194 } 195 } 196 return BiometricsProtoEnums.DETAILS_UNKNOWN; 197 } 198 toProtoWakeReasonDetailsFromFace(@uthenticateReason.Face int reason)199 private static int toProtoWakeReasonDetailsFromFace(@AuthenticateReason.Face int reason) { 200 switch (reason) { 201 case AuthenticateReason.Face.STARTED_WAKING_UP: 202 return BiometricsProtoEnums.DETAILS_FACE_STARTED_WAKING_UP; 203 case AuthenticateReason.Face.PRIMARY_BOUNCER_SHOWN: 204 return BiometricsProtoEnums.DETAILS_FACE_PRIMARY_BOUNCER_SHOWN; 205 case AuthenticateReason.Face.ASSISTANT_VISIBLE: 206 return BiometricsProtoEnums.DETAILS_FACE_ASSISTANT_VISIBLE; 207 case AuthenticateReason.Face.ALTERNATE_BIOMETRIC_BOUNCER_SHOWN: 208 return BiometricsProtoEnums.DETAILS_FACE_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN; 209 case AuthenticateReason.Face.NOTIFICATION_PANEL_CLICKED: 210 return BiometricsProtoEnums.DETAILS_FACE_NOTIFICATION_PANEL_CLICKED; 211 case AuthenticateReason.Face.OCCLUDING_APP_REQUESTED: 212 return BiometricsProtoEnums.DETAILS_FACE_OCCLUDING_APP_REQUESTED; 213 case AuthenticateReason.Face.PICK_UP_GESTURE_TRIGGERED: 214 return BiometricsProtoEnums.DETAILS_FACE_PICK_UP_GESTURE_TRIGGERED; 215 case AuthenticateReason.Face.QS_EXPANDED: 216 return BiometricsProtoEnums.DETAILS_FACE_QS_EXPANDED; 217 case AuthenticateReason.Face.SWIPE_UP_ON_BOUNCER: 218 return BiometricsProtoEnums.DETAILS_FACE_SWIPE_UP_ON_BOUNCER; 219 case AuthenticateReason.Face.UDFPS_POINTER_DOWN: 220 return BiometricsProtoEnums.DETAILS_FACE_UDFPS_POINTER_DOWN; 221 default: 222 return BiometricsProtoEnums.DETAILS_UNKNOWN; 223 } 224 } 225 226 /** {@see FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED}. */ reportUnknownTemplateEnrolledHal(int statsModality)227 public void reportUnknownTemplateEnrolledHal(int statsModality) { 228 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, 229 statsModality, 230 BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL, 231 -1 /* sensorId */); 232 } 233 234 /** {@see FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED}. */ reportUnknownTemplateEnrolledFramework(int statsModality)235 public void reportUnknownTemplateEnrolledFramework(int statsModality) { 236 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, 237 statsModality, 238 BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK, 239 -1 /* sensorId */); 240 } 241 sanitizeLatency(long latency)242 private long sanitizeLatency(long latency) { 243 if (latency < 0) { 244 Slog.w(TAG, "found a negative latency : " + latency); 245 return -1; 246 } 247 return latency; 248 } 249 sessionType(@perationReason byte reason)250 private static int sessionType(@OperationReason byte reason) { 251 if (reason == OperationReason.BIOMETRIC_PROMPT) { 252 return BiometricsProtoEnums.SESSION_TYPE_BIOMETRIC_PROMPT; 253 } 254 if (reason == OperationReason.KEYGUARD) { 255 return BiometricsProtoEnums.SESSION_TYPE_KEYGUARD_ENTRY; 256 } 257 return BiometricsProtoEnums.SESSION_TYPE_UNKNOWN; 258 } 259 orientationType(@urface.Rotation int rotation)260 private static int orientationType(@Surface.Rotation int rotation) { 261 switch (rotation) { 262 case Surface.ROTATION_0: 263 return BiometricsProtoEnums.ORIENTATION_0; 264 case Surface.ROTATION_90: 265 return BiometricsProtoEnums.ORIENTATION_90; 266 case Surface.ROTATION_180: 267 return BiometricsProtoEnums.ORIENTATION_180; 268 case Surface.ROTATION_270: 269 return BiometricsProtoEnums.ORIENTATION_270; 270 } 271 return BiometricsProtoEnums.ORIENTATION_UNKNOWN; 272 } 273 foldType(int foldType)274 private static int foldType(int foldType) { 275 switch (foldType) { 276 case IBiometricContextListener.FoldState.FULLY_CLOSED: 277 return BiometricsProtoEnums.FOLD_CLOSED; 278 case IBiometricContextListener.FoldState.FULLY_OPENED: 279 return BiometricsProtoEnums.FOLD_OPEN; 280 case IBiometricContextListener.FoldState.HALF_OPENED: 281 return BiometricsProtoEnums.FOLD_HALF_OPEN; 282 } 283 return BiometricsProtoEnums.FOLD_UNKNOWN; 284 } 285 } 286