Add logging for Biometrics
Bug: 117060268
Bug: 120161047
Test: With LoggableMonitor DEBUG turned on, manually tested and checked
logs
Change-Id: Ib8b3ec9ed7913e38b17597ac7eda535925e1576a
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index eaa7a83..bd4acdb 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
import android.os.RemoteException;
import android.security.KeyStore;
@@ -71,6 +72,11 @@
stop(false /* initiatedByClient */);
}
+ @Override
+ protected int statsAction() {
+ return BiometricsProtoEnums.ACTION_AUTHENTICATE;
+ }
+
public boolean isBiometricPrompt() {
return getCookie() != 0;
}
@@ -80,8 +86,16 @@
}
@Override
+ protected boolean isCryptoOperation() {
+ return mOpId != 0;
+ }
+
+ @Override
public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
+ super.logOnAuthenticated(authenticated, mRequireConfirmation, getTargetUserId(),
+ isBiometricPrompt());
+
final BiometricServiceBase.ServiceListener listener = getListener();
mMetricsLogger.action(mMetrics.actionBiometricAuth(), authenticated);
@@ -142,10 +156,7 @@
final int errorCode = lockoutMode == LOCKOUT_TIMED
? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
: BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
- if (listener != null) {
- listener.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */,
- getCookie());
- }
+ onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
} else {
// Don't send onAuthenticationFailed if we're in lockout, it causes a
// janky UI on Keyguard/BiometricPrompt since "authentication failed"
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 15d66e6..3ee1a04 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -41,6 +41,7 @@
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricSourceType;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceReceiver;
@@ -64,6 +65,7 @@
import android.text.TextUtils;
import android.util.Pair;
import android.util.Slog;
+import android.util.StatsLog;
import com.android.internal.R;
import com.android.internal.statusbar.IStatusBarService;
@@ -309,6 +311,7 @@
// Continue authentication with the same modality/modalities after "try again" is
// pressed
final int mModality;
+ final boolean mRequireConfirmation;
// The current state, which can be either idle, called, or started
private int mState = STATE_AUTH_IDLE;
@@ -316,10 +319,13 @@
// the authentication.
byte[] mTokenEscrow;
+ // Timestamp when hardware authentication occurred
+ private long mAuthenticatedTimeMs;
+
AuthSession(HashMap<Integer, Integer> modalities, IBinder token, long sessionId,
int userId, IBiometricServiceReceiver receiver, String opPackageName,
Bundle bundle, int callingUid, int callingPid, int callingUserId,
- int modality) {
+ int modality, boolean requireConfirmation) {
mModalitiesWaiting = modalities;
mToken = token;
mSessionId = sessionId;
@@ -331,6 +337,11 @@
mCallingPid = callingPid;
mCallingUserId = callingUserId;
mModality = modality;
+ mRequireConfirmation = requireConfirmation;
+ }
+
+ boolean isCrypto() {
+ return mSessionId != 0;
}
boolean containsCookie(int cookie) {
@@ -412,6 +423,7 @@
mCurrentAuthSession.mState = STATE_AUTH_IDLE;
mCurrentAuthSession = null;
} else {
+ mCurrentAuthSession.mAuthenticatedTimeMs = System.currentTimeMillis();
// Store the auth token and submit it to keystore after the confirmation
// button has been pressed.
mCurrentAuthSession.mTokenEscrow = token;
@@ -557,6 +569,8 @@
return;
}
+ logDialogDismissed(reason);
+
if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
// Positive button is used by passive modalities as a "confirm" button,
// do not send to client
@@ -599,6 +613,77 @@
mCurrentAuthSession.mModality);
});
}
+
+ private void logDialogDismissed(int reason) {
+ if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+ // Explicit auth, authentication confirmed.
+ // Latency in this case is authenticated -> confirmed. <Biometric>Service
+ // should have the first half (first acquired -> authenticated).
+ final long latency = System.currentTimeMillis()
+ - mCurrentAuthSession.mAuthenticatedTimeMs;
+
+ if (LoggableMonitor.DEBUG) {
+ Slog.v(LoggableMonitor.TAG, "Confirmed! Modality: " + statsModality()
+ + ", User: " + mCurrentAuthSession.mUserId
+ + ", IsCrypto: " + mCurrentAuthSession.isCrypto()
+ + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
+ + ", RequireConfirmation: "
+ + mCurrentAuthSession.mRequireConfirmation
+ + ", State: " + StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED
+ + ", Latency: " + latency);
+ }
+
+ StatsLog.write(StatsLog.BIOMETRIC_AUTHENTICATED,
+ statsModality(),
+ mCurrentAuthSession.mUserId,
+ mCurrentAuthSession.isCrypto(),
+ BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
+ mCurrentAuthSession.mRequireConfirmation,
+ StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED,
+ latency);
+ } else {
+ int error = reason == BiometricPrompt.DISMISSED_REASON_NEGATIVE
+ ? BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON
+ : reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL
+ ? BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED
+ : 0;
+ if (LoggableMonitor.DEBUG) {
+ Slog.v(LoggableMonitor.TAG, "Dismissed! Modality: " + statsModality()
+ + ", User: " + mCurrentAuthSession.mUserId
+ + ", IsCrypto: " + mCurrentAuthSession.isCrypto()
+ + ", Action: " + BiometricsProtoEnums.ACTION_AUTHENTICATE
+ + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
+ + ", Error: " + error);
+ }
+ // Auth canceled
+ StatsLog.write(StatsLog.BIOMETRIC_ERROR_OCCURRED,
+ statsModality(),
+ mCurrentAuthSession.mUserId,
+ mCurrentAuthSession.isCrypto(),
+ BiometricsProtoEnums.ACTION_AUTHENTICATE,
+ BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
+ error,
+ 0 /* vendorCode */);
+ }
+ }
+
+ private int statsModality() {
+ int modality = 0;
+ if (mCurrentAuthSession == null) {
+ return BiometricsProtoEnums.MODALITY_UNKNOWN;
+ }
+ if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FINGERPRINT)
+ != 0) {
+ modality |= BiometricsProtoEnums.MODALITY_FINGERPRINT;
+ }
+ if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_IRIS) != 0) {
+ modality |= BiometricsProtoEnums.MODALITY_IRIS;
+ }
+ if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FACE) != 0) {
+ modality |= BiometricsProtoEnums.MODALITY_FACE;
+ }
+ return modality;
+ }
};
@Override // Binder call
@@ -815,7 +900,11 @@
try {
boolean requireConfirmation = bundle.getBoolean(
BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
-
+ if ((modality & TYPE_FACE) != 0) {
+ // Check if the user has forced confirmation to be required in Settings.
+ requireConfirmation = requireConfirmation
+ || mSettingObserver.getFaceAlwaysRequireConfirmation();
+ }
// Generate random cookies to pass to the services that should prepare to start
// authenticating. Store the cookie here and wait for all services to "ack"
// with the cookie. Once all cookies are received, we can show the prompt
@@ -827,7 +916,7 @@
authenticators.put(modality, cookie);
mPendingAuthSession = new AuthSession(authenticators, token, sessionId, userId,
receiver, opPackageName, bundle, callingUid, callingPid, callingUserId,
- modality);
+ modality, requireConfirmation);
mPendingAuthSession.mState = STATE_AUTH_CALLED;
// No polymorphism :(
if ((modality & TYPE_FINGERPRINT) != 0) {
@@ -839,9 +928,6 @@
Slog.w(TAG, "Iris unsupported");
}
if ((modality & TYPE_FACE) != 0) {
- // Check if the user has forced confirmation to be required in Settings.
- requireConfirmation = requireConfirmation
- || mSettingObserver.getFaceAlwaysRequireConfirmation();
mFaceService.prepareForAuthentication(requireConfirmation,
token, sessionId, userId, mInternalReceiver, opPackageName,
cookie, callingUid, callingPid, callingUserId);
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 2791165..b65535a 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -35,6 +35,7 @@
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
@@ -55,6 +56,7 @@
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import android.util.StatsLog;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
@@ -220,8 +222,16 @@
*/
protected void notifyClientActiveCallbacks(boolean isActive) {}
+ protected abstract int statsModality();
+
protected abstract class AuthenticationClientImpl extends AuthenticationClient {
+ // Used to check if the public API that was invoked was from FingerprintManager. Only
+ // to be overridden by FingerprintService.
+ protected boolean isFingerprint() {
+ return false;
+ }
+
public AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId,
boolean restricted, String owner, int cookie, boolean requireConfirmation) {
@@ -230,6 +240,19 @@
}
@Override
+ protected int statsClient() {
+ if (isKeyguard(getOwnerString())) {
+ return BiometricsProtoEnums.CLIENT_KEYGUARD;
+ } else if (isBiometricPrompt()) {
+ return BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT;
+ } else if (isFingerprint()) {
+ return BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER;
+ } else {
+ return BiometricsProtoEnums.CLIENT_UNKNOWN;
+ }
+ }
+
+ @Override
public void onStart() {
try {
mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
@@ -296,7 +319,7 @@
}
}
- protected class RemovalClientImpl extends RemovalClient {
+ protected abstract class RemovalClientImpl extends RemovalClient {
private boolean mShouldNotify;
public RemovalClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
@@ -318,7 +341,7 @@
}
}
- protected class EnumerateClientImpl extends EnumerateClient {
+ protected abstract class EnumerateClientImpl extends EnumerateClient {
public EnumerateClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
IBinder token, ServiceListener listener, int groupId, int userId,
@@ -600,6 +623,8 @@
mHALDeathCount++;
handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /*vendorCode */);
+
+ StatsLog.write(StatsLog.BIOMETRIC_HAL_DEATH_REPORTED, statsModality());
}
protected ClientMonitor getCurrentClient() {
@@ -653,7 +678,6 @@
} else {
updateActiveGroup(mCurrentUserId, null);
}
-
}
}
diff --git a/services/core/java/com/android/server/biometrics/ClientMonitor.java b/services/core/java/com/android/server/biometrics/ClientMonitor.java
index d19aff6..e80b39b 100644
--- a/services/core/java/com/android/server/biometrics/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/ClientMonitor.java
@@ -36,7 +36,7 @@
* the current client. Subclasses are responsible for coordinating the interaction with
* the biometric's HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.).
*/
-public abstract class ClientMonitor implements IBinder.DeathRecipient {
+public abstract class ClientMonitor extends LoggableMonitor implements IBinder.DeathRecipient {
protected static final int ERROR_ESRCH = 3; // Likely HAL is dead. See errno.h.
protected static final boolean DEBUG = BiometricServiceBase.DEBUG;
private static final AudioAttributes FINGERPRINT_SONFICATION_ATTRIBUTES =
@@ -157,6 +157,7 @@
* @return true if client should be removed
*/
public boolean onAcquired(int acquiredInfo, int vendorCode) {
+ super.logOnAcquired(acquiredInfo, vendorCode, getTargetUserId());
try {
if (mListener != null) {
mListener.onAcquired(getHalDeviceId(), acquiredInfo, vendorCode);
@@ -180,6 +181,7 @@
* @return true if client should be removed
*/
public boolean onError(long deviceId, int error, int vendorCode) {
+ super.logOnError(error, vendorCode, getTargetUserId());
try {
if (mListener != null) {
mListener.onError(deviceId, error, vendorCode, getCookie());
diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java
index 3ff94bc..1124b7f 100644
--- a/services/core/java/com/android/server/biometrics/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/EnrollClient.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -51,6 +52,11 @@
}
@Override
+ protected int statsAction() {
+ return BiometricsProtoEnums.ACTION_ENROLL;
+ }
+
+ @Override
public boolean onEnrollResult(BiometricAuthenticator.Identifier identifier,
int remaining) {
if (remaining == 0) {
diff --git a/services/core/java/com/android/server/biometrics/EnumerateClient.java b/services/core/java/com/android/server/biometrics/EnumerateClient.java
index df6220c..0f57f48 100644
--- a/services/core/java/com/android/server/biometrics/EnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/EnumerateClient.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -38,6 +39,11 @@
}
@Override
+ protected int statsAction() {
+ return BiometricsProtoEnums.ACTION_ENUMERATE;
+ }
+
+ @Override
public int start() {
// The biometric template ids will be removed when we get confirmation from the HAL
try {
diff --git a/services/core/java/com/android/server/biometrics/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
new file mode 100644
index 0000000..91c924d
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics;
+
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.face.FaceManager;
+import android.util.Slog;
+import android.util.StatsLog;
+
+/**
+ * Abstract class that adds logging functionality to the ClientMonitor classes.
+ */
+public abstract class LoggableMonitor {
+
+ public static final String TAG = "BiometricStats";
+ public static final boolean DEBUG = true;
+
+ private long mFirstAcquireTimeMs;
+
+ /**
+ * Only valid for AuthenticationClient.
+ * @return true if the client is authenticating for a crypto operation.
+ */
+ protected boolean isCryptoOperation() {
+ return false;
+ }
+
+ /**
+ * @return One of {@link BiometricsProtoEnums} MODALITY_* constants.
+ */
+ protected abstract int statsModality();
+
+ /**
+ * Action == enroll, authenticate, remove, enumerate.
+ * @return One of {@link BiometricsProtoEnums} ACTION_* constants.
+ */
+ protected abstract int statsAction();
+
+ /**
+ * Only matters for AuthenticationClient. Should only be overridden in
+ * {@link BiometricServiceBase}, which determines if a client is for BiometricPrompt, Keyguard,
+ * etc.
+ * @return one of {@link BiometricsProtoEnums} CLIENT_* constants.
+ */
+ protected int statsClient() {
+ return BiometricsProtoEnums.CLIENT_UNKNOWN;
+ }
+
+ protected final void logOnAcquired(int acquiredInfo, int vendorCode, int targetUserId) {
+ if (statsModality() == BiometricsProtoEnums.MODALITY_FACE) {
+ if (acquiredInfo == FaceManager.FACE_ACQUIRED_START) {
+ mFirstAcquireTimeMs = System.currentTimeMillis();
+ }
+ } else if (acquiredInfo == BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
+ if (mFirstAcquireTimeMs == 0) {
+ mFirstAcquireTimeMs = System.currentTimeMillis();
+ }
+ }
+ if (DEBUG) {
+ Slog.v(TAG, "Acquired! Modality: " + statsModality()
+ + ", User: " + targetUserId
+ + ", IsCrypto: " + isCryptoOperation()
+ + ", Action: " + statsAction()
+ + ", Client: " + statsClient()
+ + ", AcquiredInfo: " + acquiredInfo
+ + ", VendorCode: " + vendorCode);
+ }
+ StatsLog.write(StatsLog.BIOMETRIC_ACQUIRED,
+ statsModality(),
+ targetUserId,
+ isCryptoOperation(),
+ statsAction(),
+ statsClient(),
+ acquiredInfo,
+ 0 /* vendorCode */); // Don't log vendorCode for now
+ }
+
+ protected final void logOnError(int error, int vendorCode, int targetUserId) {
+ if (DEBUG) {
+ Slog.v(TAG, "Error! Modality: " + statsModality()
+ + ", User: " + targetUserId
+ + ", IsCrypto: " + isCryptoOperation()
+ + ", Action: " + statsAction()
+ + ", Client: " + statsClient()
+ + ", Error: " + error
+ + ", VendorCode: " + vendorCode);
+ }
+ StatsLog.write(StatsLog.BIOMETRIC_ERROR_OCCURRED,
+ statsModality(),
+ targetUserId,
+ isCryptoOperation(),
+ statsAction(),
+ statsClient(),
+ error,
+ vendorCode);
+ }
+
+ protected final void logOnAuthenticated(boolean authenticated, boolean requireConfirmation,
+ int targetUserId, boolean isBiometricPrompt) {
+ int authState = StatsLog.BIOMETRIC_AUTHENTICATED__STATE__UNKNOWN;
+ if (!authenticated) {
+ authState = StatsLog.BIOMETRIC_AUTHENTICATED__STATE__REJECTED;
+ } else {
+ // Authenticated
+ if (isBiometricPrompt && requireConfirmation) {
+ authState = StatsLog.BIOMETRIC_AUTHENTICATED__STATE__PENDING_CONFIRMATION;
+ } else {
+ authState = StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED;
+ }
+ }
+
+ // Only valid if we have a first acquired time, otherwise set to -1
+ final long latency = mFirstAcquireTimeMs != 0
+ ? (System.currentTimeMillis() - mFirstAcquireTimeMs)
+ : -1;
+
+ if (DEBUG) {
+ Slog.v(TAG, "Authenticated! Modality: " + statsModality()
+ + ", User: " + targetUserId
+ + ", IsCrypto: " + isCryptoOperation()
+ + ", Client: " + statsClient()
+ + ", RequireConfirmation: " + requireConfirmation
+ + ", State: " + authState
+ + ", Latency: " + latency);
+ }
+
+ StatsLog.write(StatsLog.BIOMETRIC_AUTHENTICATED,
+ statsModality(),
+ targetUserId,
+ isCryptoOperation(),
+ statsClient(),
+ requireConfirmation,
+ authState,
+ latency);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/RemovalClient.java b/services/core/java/com/android/server/biometrics/RemovalClient.java
index be233ec..0509067 100644
--- a/services/core/java/com/android/server/biometrics/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/RemovalClient.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -43,6 +44,11 @@
}
@Override
+ protected int statsAction() {
+ return BiometricsProtoEnums.ACTION_REMOVE;
+ }
+
+ @Override
public int start() {
// The biometric template ids will be removed when we get confirmation from the HAL
try {
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index d4be539..90342ee 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -27,6 +27,7 @@
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
@@ -90,6 +91,11 @@
super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
restricted, owner, cookie, requireConfirmation);
}
+
+ @Override
+ protected int statsModality() {
+ return FaceService.this.statsModality();
+ }
}
/**
@@ -126,6 +132,11 @@
public boolean shouldVibrate() {
return false;
}
+
+ @Override
+ protected int statsModality() {
+ return FaceService.this.statsModality();
+ }
};
enrollInternal(client, UserHandle.getCallingUserId());
@@ -206,7 +217,12 @@
final boolean restricted = isRestricted();
final RemovalClientImpl client = new RemovalClientImpl(getContext(), mDaemonWrapper,
mHalDeviceId, token, new ServiceListenerImpl(receiver), faceId, 0 /* groupId */,
- userId, restricted, token.toString());
+ userId, restricted, token.toString()) {
+ @Override
+ protected int statsModality() {
+ return FaceService.this.statsModality();
+ }
+ };
client.setShouldNotifyUserActivity(true);
removeInternal(client);
}
@@ -219,7 +235,12 @@
final boolean restricted = isRestricted();
final EnumerateClientImpl client = new EnumerateClientImpl(getContext(), mDaemonWrapper,
mHalDeviceId, token, new ServiceListenerImpl(receiver), userId, userId,
- restricted, getContext().getOpPackageName());
+ restricted, getContext().getOpPackageName()) {
+ @Override
+ protected int statsModality() {
+ return FaceService.this.statsModality();
+ }
+ };
enumerateInternal(client);
}
@@ -770,6 +791,11 @@
// noop for Face.
}
+ @Override
+ protected int statsModality() {
+ return BiometricsProtoEnums.MODALITY_FACE;
+ }
+
/** Gets the face daemon */
private synchronized IBiometricsFace getFaceDaemon() {
if (mDaemon == null) {
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index f84cda03..62947c7 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -30,6 +30,7 @@
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
@@ -101,6 +102,11 @@
}
private final class FingerprintAuthClient extends AuthenticationClientImpl {
+ @Override
+ protected boolean isFingerprint() {
+ return true;
+ }
+
public FingerprintAuthClient(Context context,
DaemonWrapper daemon, long halDeviceId, IBinder token,
ServiceListener listener, int targetUserId, int groupId, long opId,
@@ -109,6 +115,11 @@
super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
restricted, owner, cookie, requireConfirmation);
}
+
+ @Override
+ protected int statsModality() {
+ return FingerprintService.this.statsModality();
+ }
}
/**
@@ -147,6 +158,11 @@
public boolean shouldVibrate() {
return true;
}
+
+ @Override
+ protected int statsModality() {
+ return FingerprintService.this.statsModality();
+ }
};
enrollInternal(client, userId);
@@ -225,7 +241,12 @@
final boolean restricted = isRestricted();
final RemovalClientImpl client = new RemovalClientImpl(getContext(), mDaemonWrapper,
mHalDeviceId, token, new ServiceListenerImpl(receiver), fingerId, groupId,
- userId, restricted, token.toString());
+ userId, restricted, token.toString()) {
+ @Override
+ protected int statsModality() {
+ return FingerprintService.this.statsModality();
+ }
+ };
client.setShouldNotifyUserActivity(true);
removeInternal(client);
}
@@ -238,7 +259,12 @@
final boolean restricted = isRestricted();
final EnumerateClientImpl client = new EnumerateClientImpl(getContext(), mDaemonWrapper,
mHalDeviceId, token, new ServiceListenerImpl(receiver), userId, userId,
- restricted, getContext().getOpPackageName());
+ restricted, getContext().getOpPackageName()) {
+ @Override
+ protected int statsModality() {
+ return FingerprintService.this.statsModality();
+ }
+ };
enumerateInternal(client);
}
@@ -544,6 +570,11 @@
}
return remaining == 0;
}
+
+ @Override
+ protected int statsModality() {
+ return FingerprintService.this.statsModality();
+ }
}
/**
@@ -558,6 +589,11 @@
restricted,
owner);
}
+
+ @Override
+ protected int statsModality() {
+ return FingerprintService.this.statsModality();
+ }
}
private final FingerprintMetrics mFingerprintMetrics = new FingerprintMetrics();
@@ -885,6 +921,11 @@
}
}
+ @Override
+ protected int statsModality() {
+ return BiometricsProtoEnums.MODALITY_FINGERPRINT;
+ }
+
/** Gets the fingerprint daemon */
private synchronized IBiometricsFingerprint getFingerprintDaemon() {
if (mDaemon == null) {
diff --git a/services/core/java/com/android/server/biometrics/iris/IrisService.java b/services/core/java/com/android/server/biometrics/iris/IrisService.java
index 37cdc2a..eb457b6 100644
--- a/services/core/java/com/android/server/biometrics/iris/IrisService.java
+++ b/services/core/java/com/android/server/biometrics/iris/IrisService.java
@@ -17,6 +17,7 @@
package com.android.server.biometrics.iris;
import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
import com.android.server.biometrics.BiometricServiceBase;
import com.android.server.biometrics.BiometricUtils;
@@ -128,4 +129,9 @@
protected boolean checkAppOps(int uid, String opPackageName) {
return false;
}
+
+ @Override
+ protected int statsModality() {
+ return BiometricsProtoEnums.MODALITY_IRIS;
+ }
}