diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 2b23fe0379168..99e19313406c6 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -255,6 +255,7 @@ message Atom { AppInstallOnExternalStorageReported app_install_on_external_storage_reported = 181; NetworkStackReported network_stack_reported = 182; AppMovedStorageReported app_moved_storage_reported = 183; + BiometricEnrolled biometric_enrolled = 184; } // Pulled events will start at field 10000. @@ -3154,6 +3155,23 @@ message BiometricSystemHealthIssueDetected { optional android.hardware.biometrics.IssueEnum issue = 2; } +/** + * Logs when a biometric enrollment occurs. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/biometrics + */ +message BiometricEnrolled { + // Biometric modality that was used. + optional android.hardware.biometrics.ModalityEnum modality = 1; + // The associated user. Eg: 0 for owners, 10+ for others. Defined in android/os/UserHandle.java + optional int32 user = 2; + // The amount of time the enrollment took in milliseconds. + optional int64 latency_millis = 3; + // Whether or not the enrollment was successful. + optional bool success = 4; +} + message Notification { // Type of notification event. diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java index d5e626a8b9fe8..e656d98095824 100644 --- a/services/core/java/com/android/server/biometrics/EnrollClient.java +++ b/services/core/java/com/android/server/biometrics/EnrollClient.java @@ -36,6 +36,7 @@ public abstract class EnrollClient extends ClientMonitor { private final byte[] mCryptoToken; private final BiometricUtils mBiometricUtils; private final int[] mDisabledFeatures; + private long mEnrollmentStartTimeMs; public abstract boolean shouldVibrate(); @@ -61,6 +62,9 @@ public abstract class EnrollClient extends ClientMonitor { int remaining) { if (remaining == 0) { mBiometricUtils.addBiometricForUser(getContext(), getTargetUserId(), identifier); + logOnEnrolled(getTargetUserId(), + System.currentTimeMillis() - mEnrollmentStartTimeMs, + true /* enrollSuccessful */); } notifyUserActivity(); return sendEnrollResult(identifier, remaining); @@ -89,6 +93,7 @@ public abstract class EnrollClient extends ClientMonitor { @Override public int start() { + mEnrollmentStartTimeMs = System.currentTimeMillis(); final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); try { final ArrayList disabledFeatures = new ArrayList<>(); @@ -127,10 +132,6 @@ public abstract class EnrollClient extends ClientMonitor { } catch (RemoteException e) { Slog.e(getLogTag(), "stopEnrollment failed", e); } - if (initiatedByClient) { - onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_CANCELED, - 0 /* vendorCode */); - } mAlreadyCancelled = true; return 0; } @@ -155,4 +156,17 @@ public abstract class EnrollClient extends ClientMonitor { return true; // Invalid for EnrollClient } + /** + * Called when we get notification from the biometric's HAL that an error has occurred with the + * current operation. Common to authenticate, enroll, enumerate and remove. + * @param error + * @return true if client should be removed + */ + @Override + public boolean onError(long deviceId, int error, int vendorCode) { + logOnEnrolled(getTargetUserId(), System.currentTimeMillis() - mEnrollmentStartTimeMs, + false /* enrollSuccessful */); + return super.onError(deviceId, error, vendorCode); + } + } diff --git a/services/core/java/com/android/server/biometrics/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/LoggableMonitor.java index 3b75b95fb0b99..b0577cd79ac45 100644 --- a/services/core/java/com/android/server/biometrics/LoggableMonitor.java +++ b/services/core/java/com/android/server/biometrics/LoggableMonitor.java @@ -150,4 +150,23 @@ public abstract class LoggableMonitor { authState, latency); } + + protected final void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) { + if (DEBUG) { + Slog.v(TAG, "Enrolled! Modality: " + statsModality() + + ", User: " + targetUserId + + ", Client: " + statsClient() + + ", Latency: " + latency + + ", Success: " + enrollSuccessful); + } else { + Slog.v(TAG, "Enroll latency: " + latency); + } + + StatsLog.write(StatsLog.BIOMETRIC_ENROLLED, + statsModality(), + targetUserId, + latency, + enrollSuccessful); + } + }