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