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