1 /* 2 * Copyright (C) 2019 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; 18 19 import android.content.Context; 20 import android.hardware.biometrics.BiometricConstants; 21 import android.hardware.biometrics.BiometricsProtoEnums; 22 import android.hardware.face.FaceManager; 23 import android.util.Slog; 24 import android.util.StatsLog; 25 26 /** 27 * Abstract class that adds logging functionality to the ClientMonitor classes. 28 */ 29 public abstract class LoggableMonitor { 30 31 public static final String TAG = "BiometricStats"; 32 public static final boolean DEBUG = false; 33 34 private long mFirstAcquireTimeMs; 35 getFirstAcquireTimeMs()36 protected long getFirstAcquireTimeMs() { 37 return mFirstAcquireTimeMs; 38 } 39 40 /** 41 * Only valid for AuthenticationClient. 42 * @return true if the client is authenticating for a crypto operation. 43 */ isCryptoOperation()44 protected boolean isCryptoOperation() { 45 return false; 46 } 47 48 /** 49 * @return One of {@link BiometricsProtoEnums} MODALITY_* constants. 50 */ statsModality()51 protected abstract int statsModality(); 52 53 /** 54 * Action == enroll, authenticate, remove, enumerate. 55 * @return One of {@link BiometricsProtoEnums} ACTION_* constants. 56 */ statsAction()57 protected abstract int statsAction(); 58 59 /** 60 * Only matters for AuthenticationClient. Should only be overridden in 61 * {@link BiometricServiceBase}, which determines if a client is for BiometricPrompt, Keyguard, 62 * etc. 63 * @return one of {@link BiometricsProtoEnums} CLIENT_* constants. 64 */ statsClient()65 protected int statsClient() { 66 return BiometricsProtoEnums.CLIENT_UNKNOWN; 67 } 68 logOnAcquired(Context context, int acquiredInfo, int vendorCode, int targetUserId)69 protected final void logOnAcquired(Context context, int acquiredInfo, int vendorCode, 70 int targetUserId) { 71 if (statsModality() == BiometricsProtoEnums.MODALITY_FACE) { 72 if (acquiredInfo == FaceManager.FACE_ACQUIRED_START) { 73 mFirstAcquireTimeMs = System.currentTimeMillis(); 74 } 75 } else if (acquiredInfo == BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) { 76 if (mFirstAcquireTimeMs == 0) { 77 mFirstAcquireTimeMs = System.currentTimeMillis(); 78 } 79 } 80 if (DEBUG) { 81 Slog.v(TAG, "Acquired! Modality: " + statsModality() 82 + ", User: " + targetUserId 83 + ", IsCrypto: " + isCryptoOperation() 84 + ", Action: " + statsAction() 85 + ", Client: " + statsClient() 86 + ", AcquiredInfo: " + acquiredInfo 87 + ", VendorCode: " + vendorCode); 88 } 89 StatsLog.write(StatsLog.BIOMETRIC_ACQUIRED, 90 statsModality(), 91 targetUserId, 92 isCryptoOperation(), 93 statsAction(), 94 statsClient(), 95 acquiredInfo, 96 vendorCode, 97 Utils.isDebugEnabled(context, targetUserId)); 98 } 99 logOnError(Context context, int error, int vendorCode, int targetUserId)100 protected final void logOnError(Context context, int error, int vendorCode, int targetUserId) { 101 102 final long latency = mFirstAcquireTimeMs != 0 103 ? (System.currentTimeMillis() - mFirstAcquireTimeMs) : -1; 104 105 if (DEBUG) { 106 Slog.v(TAG, "Error! Modality: " + statsModality() 107 + ", User: " + targetUserId 108 + ", IsCrypto: " + isCryptoOperation() 109 + ", Action: " + statsAction() 110 + ", Client: " + statsClient() 111 + ", Error: " + error 112 + ", VendorCode: " + vendorCode 113 + ", Latency: " + latency); 114 } else { 115 Slog.v(TAG, "Error latency: " + latency); 116 } 117 StatsLog.write(StatsLog.BIOMETRIC_ERROR_OCCURRED, 118 statsModality(), 119 targetUserId, 120 isCryptoOperation(), 121 statsAction(), 122 statsClient(), 123 error, 124 vendorCode, 125 Utils.isDebugEnabled(context, targetUserId), 126 latency); 127 } 128 logOnAuthenticated(Context context, boolean authenticated, boolean requireConfirmation, int targetUserId, boolean isBiometricPrompt)129 protected final void logOnAuthenticated(Context context, boolean authenticated, 130 boolean requireConfirmation, int targetUserId, boolean isBiometricPrompt) { 131 int authState = StatsLog.BIOMETRIC_AUTHENTICATED__STATE__UNKNOWN; 132 if (!authenticated) { 133 authState = StatsLog.BIOMETRIC_AUTHENTICATED__STATE__REJECTED; 134 } else { 135 // Authenticated 136 if (isBiometricPrompt && requireConfirmation) { 137 authState = StatsLog.BIOMETRIC_AUTHENTICATED__STATE__PENDING_CONFIRMATION; 138 } else { 139 authState = StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED; 140 } 141 } 142 143 // Only valid if we have a first acquired time, otherwise set to -1 144 final long latency = mFirstAcquireTimeMs != 0 145 ? (System.currentTimeMillis() - mFirstAcquireTimeMs) 146 : -1; 147 148 if (DEBUG) { 149 Slog.v(TAG, "Authenticated! Modality: " + statsModality() 150 + ", User: " + targetUserId 151 + ", IsCrypto: " + isCryptoOperation() 152 + ", Client: " + statsClient() 153 + ", RequireConfirmation: " + requireConfirmation 154 + ", State: " + authState 155 + ", Latency: " + latency); 156 } else { 157 Slog.v(TAG, "Authentication latency: " + latency); 158 } 159 160 StatsLog.write(StatsLog.BIOMETRIC_AUTHENTICATED, 161 statsModality(), 162 targetUserId, 163 isCryptoOperation(), 164 statsClient(), 165 requireConfirmation, 166 authState, 167 latency, 168 Utils.isDebugEnabled(context, targetUserId)); 169 } 170 logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful)171 protected final void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) { 172 if (DEBUG) { 173 Slog.v(TAG, "Enrolled! Modality: " + statsModality() 174 + ", User: " + targetUserId 175 + ", Client: " + statsClient() 176 + ", Latency: " + latency 177 + ", Success: " + enrollSuccessful); 178 } else { 179 Slog.v(TAG, "Enroll latency: " + latency); 180 } 181 182 StatsLog.write(StatsLog.BIOMETRIC_ENROLLED, 183 statsModality(), 184 targetUserId, 185 latency, 186 enrollSuccessful); 187 } 188 189 } 190