Merge "[1/n] FRR data capture" into udc-qpr-dev
This commit is contained in:
@@ -5336,6 +5336,12 @@
|
||||
<!-- Default value for performant auth feature. -->
|
||||
<bool name="config_performantAuthDefault">false</bool>
|
||||
|
||||
<!-- Threshold for false rejection rate (FRR) of biometric authentication. Applies for both
|
||||
fingerprint and face. If a dual-modality device only enrolled a single biometric and
|
||||
experiences high FRR (above threshold), system notification will be sent to encourage user
|
||||
to enroll the other eligible biometric. -->
|
||||
<fraction name="config_biometricNotificationFrrThreshold">30%</fraction>
|
||||
|
||||
<!-- The component name for the default profile supervisor, which can be set as a profile owner
|
||||
even after user setup is complete. The defined component should be used for supervision purposes
|
||||
only. The component must be part of a system app. -->
|
||||
|
||||
@@ -2581,6 +2581,9 @@
|
||||
<java-symbol type="string" name="biometric_error_device_not_secured" />
|
||||
<java-symbol type="string" name="biometric_error_generic" />
|
||||
|
||||
<!-- Biometric FRR config -->
|
||||
<java-symbol type="fraction" name="config_biometricNotificationFrrThreshold" />
|
||||
|
||||
<!-- Device credential strings for BiometricManager -->
|
||||
<java-symbol type="string" name="screen_lock_app_setting_name" />
|
||||
<java-symbol type="string" name="screen_lock_dialog_default_subtitle" />
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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;
|
||||
|
||||
/**
|
||||
* Utility class for on-device biometric authentication data, including total authentication,
|
||||
* rejections, and the number of sent enrollment notifications.
|
||||
*/
|
||||
public class AuthenticationStats {
|
||||
|
||||
private final int mUserId;
|
||||
private int mTotalAttempts;
|
||||
private int mRejectedAttempts;
|
||||
private int mEnrollmentNotifications;
|
||||
private final int mModality;
|
||||
|
||||
public AuthenticationStats(final int userId, int totalAttempts, int rejectedAttempts,
|
||||
int enrollmentNotifications, final int modality) {
|
||||
mUserId = userId;
|
||||
mTotalAttempts = totalAttempts;
|
||||
mRejectedAttempts = rejectedAttempts;
|
||||
mEnrollmentNotifications = enrollmentNotifications;
|
||||
mModality = modality;
|
||||
}
|
||||
|
||||
public AuthenticationStats(final int userId, final int modality) {
|
||||
mUserId = userId;
|
||||
mTotalAttempts = 0;
|
||||
mRejectedAttempts = 0;
|
||||
mEnrollmentNotifications = 0;
|
||||
mModality = modality;
|
||||
}
|
||||
|
||||
public int getUserId() {
|
||||
return mUserId;
|
||||
}
|
||||
|
||||
public int getTotalAttempts() {
|
||||
return mTotalAttempts;
|
||||
}
|
||||
|
||||
public int getRejectedAttempts() {
|
||||
return mRejectedAttempts;
|
||||
}
|
||||
|
||||
public int getEnrollmentNotifications() {
|
||||
return mEnrollmentNotifications;
|
||||
}
|
||||
|
||||
public int getModality() {
|
||||
return mModality;
|
||||
}
|
||||
|
||||
/** Calculate FRR. */
|
||||
public float getFrr() {
|
||||
if (mTotalAttempts > 0) {
|
||||
return mRejectedAttempts / (float) mTotalAttempts;
|
||||
} else {
|
||||
return -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/** Update total authentication attempts and rejections. */
|
||||
public void authenticate(boolean authenticated) {
|
||||
if (!authenticated) {
|
||||
mRejectedAttempts++;
|
||||
}
|
||||
mTotalAttempts++;
|
||||
}
|
||||
|
||||
/** Reset total authentication attempts and rejections. */
|
||||
public void resetData() {
|
||||
mTotalAttempts = 0;
|
||||
mRejectedAttempts = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Calculate and collect on-device False Rejection Rates (FRR).
|
||||
* FRR = All [given biometric modality] unlock failures / all [given biometric modality] unlock
|
||||
* attempts.
|
||||
*/
|
||||
public class AuthenticationStatsCollector {
|
||||
|
||||
private static final String TAG = "AuthenticationStatsCollector";
|
||||
|
||||
// The minimum number of attempts that will calculate the FRR and trigger the notification.
|
||||
private static final int MINIMUM_ATTEMPTS = 500;
|
||||
// The maximum number of eligible biometric enrollment notification can be sent.
|
||||
private static final int MAXIMUM_ENROLLMENT_NOTIFICATIONS = 2;
|
||||
|
||||
private final float mThreshold;
|
||||
private final int mModality;
|
||||
|
||||
@NonNull private final Map<Integer, AuthenticationStats> mUserAuthenticationStatsMap;
|
||||
|
||||
public AuthenticationStatsCollector(@NonNull Context context, int modality) {
|
||||
mThreshold = context.getResources()
|
||||
.getFraction(R.fraction.config_biometricNotificationFrrThreshold, 1, 1);
|
||||
mUserAuthenticationStatsMap = new HashMap<>();
|
||||
mModality = modality;
|
||||
}
|
||||
|
||||
/** Update total authentication and rejected attempts. */
|
||||
public void authenticate(int userId, boolean authenticated) {
|
||||
// Check if this is a new user.
|
||||
if (!mUserAuthenticationStatsMap.containsKey(userId)) {
|
||||
mUserAuthenticationStatsMap.put(userId, new AuthenticationStats(userId, mModality));
|
||||
}
|
||||
|
||||
AuthenticationStats authenticationStats = mUserAuthenticationStatsMap.get(userId);
|
||||
|
||||
authenticationStats.authenticate(authenticated);
|
||||
|
||||
persistDataIfNeeded(userId);
|
||||
sendNotificationIfNeeded(userId);
|
||||
}
|
||||
|
||||
private void sendNotificationIfNeeded(int userId) {
|
||||
AuthenticationStats authenticationStats = mUserAuthenticationStatsMap.get(userId);
|
||||
if (authenticationStats.getTotalAttempts() >= MINIMUM_ATTEMPTS) {
|
||||
// Send notification if FRR exceeds the threshold
|
||||
if (authenticationStats.getEnrollmentNotifications() < MAXIMUM_ENROLLMENT_NOTIFICATIONS
|
||||
&& authenticationStats.getFrr() >= mThreshold) {
|
||||
// TODO(wenhuiy): Send notifications.
|
||||
}
|
||||
|
||||
authenticationStats.resetData();
|
||||
}
|
||||
}
|
||||
|
||||
private void persistDataIfNeeded(int userId) {
|
||||
AuthenticationStats authenticationStats = mUserAuthenticationStatsMap.get(userId);
|
||||
if (authenticationStats.getTotalAttempts() % 50 == 0) {
|
||||
// TODO(wenhuiy): Persist data.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only being used in tests. Callers should not make any changes to the returned
|
||||
* authentication stats.
|
||||
*
|
||||
* @return AuthenticationStats of the user, or null if the stats doesn't exist.
|
||||
*/
|
||||
@Nullable
|
||||
@VisibleForTesting
|
||||
AuthenticationStats getAuthenticationStatsForUser(int userId) {
|
||||
return mUserAuthenticationStatsMap.getOrDefault(userId, null);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setAuthenticationStatsForUser(int userId, AuthenticationStats authenticationStats) {
|
||||
mUserAuthenticationStatsMap.put(userId, authenticationStats);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.server.biometrics.AuthenticationStatsCollector;
|
||||
import com.android.server.biometrics.Utils;
|
||||
|
||||
/**
|
||||
@@ -41,6 +42,7 @@ public class BiometricLogger {
|
||||
private final int mStatsAction;
|
||||
private final int mStatsClient;
|
||||
private final BiometricFrameworkStatsLogger mSink;
|
||||
@NonNull private final AuthenticationStatsCollector mAuthenticationStatsCollector;
|
||||
@NonNull private final ALSProbe mALSProbe;
|
||||
|
||||
private long mFirstAcquireTimeMs;
|
||||
@@ -49,7 +51,8 @@ public class BiometricLogger {
|
||||
/** Get a new logger with all unknown fields (for operations that do not require logs). */
|
||||
public static BiometricLogger ofUnknown(@NonNull Context context) {
|
||||
return new BiometricLogger(context, BiometricsProtoEnums.MODALITY_UNKNOWN,
|
||||
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
|
||||
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
null /* AuthenticationStatsCollector */);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,26 +67,32 @@ public class BiometricLogger {
|
||||
* @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants.
|
||||
*/
|
||||
public BiometricLogger(
|
||||
@NonNull Context context, int statsModality, int statsAction, int statsClient) {
|
||||
@NonNull Context context, int statsModality, int statsAction, int statsClient,
|
||||
AuthenticationStatsCollector authenticationStatsCollector) {
|
||||
this(statsModality, statsAction, statsClient,
|
||||
BiometricFrameworkStatsLogger.getInstance(),
|
||||
authenticationStatsCollector,
|
||||
context.getSystemService(SensorManager.class));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
BiometricLogger(
|
||||
int statsModality, int statsAction, int statsClient,
|
||||
BiometricFrameworkStatsLogger logSink, SensorManager sensorManager) {
|
||||
BiometricFrameworkStatsLogger logSink,
|
||||
@NonNull AuthenticationStatsCollector statsCollector,
|
||||
SensorManager sensorManager) {
|
||||
mStatsModality = statsModality;
|
||||
mStatsAction = statsAction;
|
||||
mStatsClient = statsClient;
|
||||
mSink = logSink;
|
||||
mAuthenticationStatsCollector = statsCollector;
|
||||
mALSProbe = new ALSProbe(sensorManager);
|
||||
}
|
||||
|
||||
/** Creates a new logger with the action replaced with the new action. */
|
||||
public BiometricLogger swapAction(@NonNull Context context, int statsAction) {
|
||||
return new BiometricLogger(context, mStatsModality, statsAction, mStatsClient);
|
||||
return new BiometricLogger(context, mStatsModality, statsAction, mStatsClient,
|
||||
null /* AuthenticationStatsCollector */);
|
||||
}
|
||||
|
||||
/** Disable logging metrics and only log critical events, such as system health issues. */
|
||||
@@ -192,10 +201,13 @@ public class BiometricLogger {
|
||||
public void logOnAuthenticated(Context context, OperationContextExt operationContext,
|
||||
boolean authenticated, boolean requireConfirmation, int targetUserId,
|
||||
boolean isBiometricPrompt) {
|
||||
// Do not log metrics when fingerprint enrollment reason is ENROLL_FIND_SENSOR
|
||||
if (!mShouldLogMetrics) {
|
||||
return;
|
||||
}
|
||||
|
||||
mAuthenticationStatsCollector.authenticate(targetUserId, authenticated);
|
||||
|
||||
int authState = FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__UNKNOWN;
|
||||
if (!authenticated) {
|
||||
authState = FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__REJECTED;
|
||||
|
||||
@@ -49,6 +49,7 @@ import android.util.proto.ProtoOutputStream;
|
||||
import android.view.Surface;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.biometrics.AuthenticationStatsCollector;
|
||||
import com.android.server.biometrics.Utils;
|
||||
import com.android.server.biometrics.log.BiometricContext;
|
||||
import com.android.server.biometrics.log.BiometricLogger;
|
||||
@@ -112,6 +113,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
private final BiometricContext mBiometricContext;
|
||||
@NonNull
|
||||
private final AuthSessionCoordinator mAuthSessionCoordinator;
|
||||
@NonNull
|
||||
private final AuthenticationStatsCollector mAuthenticationStatsCollector;
|
||||
@Nullable
|
||||
private IFace mDaemon;
|
||||
|
||||
@@ -173,6 +176,9 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator();
|
||||
mDaemon = daemon;
|
||||
|
||||
mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
|
||||
BiometricsProtoEnums.MODALITY_FACE);
|
||||
|
||||
for (SensorProps prop : props) {
|
||||
final int sensorId = prop.commonProps.sensorId;
|
||||
|
||||
@@ -283,7 +289,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
mContext, mFaceSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
mFaceSensors.get(sensorId).getAuthenticatorIds());
|
||||
|
||||
@@ -341,7 +348,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
final FaceInvalidationClient client = new FaceInvalidationClient(mContext,
|
||||
mFaceSensors.get(sensorId).getLazySession(), userId, sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
mFaceSensors.get(sensorId).getAuthenticatorIds(), callback);
|
||||
scheduleForSensor(sensorId, client);
|
||||
@@ -372,7 +380,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
mFaceSensors.get(sensorId).getLazySession(), token,
|
||||
new ClientMonitorCallbackConverter(receiver), userId, opPackageName, sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
@@ -386,7 +395,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
mFaceSensors.get(sensorId).getLazySession(), token, userId,
|
||||
opPackageName, sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, challenge);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
@@ -407,7 +417,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
opPackageName, id, FaceUtils.getInstance(sensorId), disabledFeatures,
|
||||
ENROLL_TIMEOUT_SEC, previewSurface, sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_ENROLL,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, maxTemplatesPerUser, debugConsent);
|
||||
scheduleForSensor(sensorId, client, new ClientMonitorCompositeCallback(
|
||||
mBiometricStateCallback, new ClientMonitorCallback() {
|
||||
@@ -443,7 +454,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
final FaceDetectClient client = new FaceDetectClient(mContext,
|
||||
mFaceSensors.get(sensorId).getLazySession(),
|
||||
token, id, callback, options,
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, isStrongBiometric);
|
||||
scheduleForSensor(sensorId, client, mBiometricStateCallback);
|
||||
});
|
||||
@@ -471,7 +483,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
mContext, mFaceSensors.get(sensorId).getLazySession(), token, requestId,
|
||||
callback, operationId, restricted, options, cookie,
|
||||
false /* requireConfirmation */,
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, isStrongBiometric,
|
||||
mUsageStats, mFaceSensors.get(sensorId).getLockoutCache(),
|
||||
allowBackgroundAuthentication, Utils.getCurrentStrength(sensorId));
|
||||
@@ -540,7 +553,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
new ClientMonitorCallbackConverter(receiver), faceIds, userId,
|
||||
opPackageName, FaceUtils.getInstance(sensorId), sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_REMOVE,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
mFaceSensors.get(sensorId).getAuthenticatorIds());
|
||||
scheduleForSensor(sensorId, client, mBiometricStateCallback);
|
||||
@@ -554,7 +568,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
mContext, mFaceSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, hardwareAuthToken,
|
||||
mFaceSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher,
|
||||
Utils.getCurrentStrength(sensorId));
|
||||
@@ -624,7 +639,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
mFaceSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_ENUMERATE,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
FaceUtils.getInstance(sensorId),
|
||||
mFaceSensors.get(sensorId).getAuthenticatorIds());
|
||||
@@ -636,9 +652,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
});
|
||||
}
|
||||
|
||||
private BiometricLogger createLogger(int statsAction, int statsClient) {
|
||||
private BiometricLogger createLogger(int statsAction, int statsClient,
|
||||
AuthenticationStatsCollector authenticationStatsCollector) {
|
||||
return new BiometricLogger(mContext, BiometricsProtoEnums.MODALITY_FACE,
|
||||
statsAction, statsClient);
|
||||
statsAction, statsClient, authenticationStatsCollector);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -52,6 +52,7 @@ import android.view.Surface;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.server.biometrics.AuthenticationStatsCollector;
|
||||
import com.android.server.biometrics.SensorServiceStateProto;
|
||||
import com.android.server.biometrics.SensorStateProto;
|
||||
import com.android.server.biometrics.UserStateProto;
|
||||
@@ -124,6 +125,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
@Nullable private IBiometricsFace mDaemon;
|
||||
@NonNull private final HalResultController mHalResultController;
|
||||
@NonNull private final BiometricContext mBiometricContext;
|
||||
@NonNull private final AuthenticationStatsCollector mAuthenticationStatsCollector;
|
||||
// for requests that do not use biometric prompt
|
||||
@NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
|
||||
private int mCurrentUserId = UserHandle.USER_NULL;
|
||||
@@ -364,6 +366,9 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
mCurrentUserId = UserHandle.USER_NULL;
|
||||
});
|
||||
|
||||
mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
|
||||
BiometricsProtoEnums.MODALITY_FACE);
|
||||
|
||||
try {
|
||||
ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
|
||||
} catch (RemoteException e) {
|
||||
@@ -554,7 +559,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
|
||||
opPackageName, mSensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext, sSystemClock.millis());
|
||||
mGeneratedChallengeCache = client;
|
||||
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
|
||||
@@ -586,7 +591,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
|
||||
mLazyDaemon, token, userId, opPackageName, mSensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext);
|
||||
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
|
||||
@Override
|
||||
@@ -617,7 +622,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
opPackageName, id, FaceUtils.getLegacyInstance(mSensorId), disabledFeatures,
|
||||
ENROLL_TIMEOUT_SEC, previewSurface, mSensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_ENROLL,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext);
|
||||
|
||||
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
|
||||
@@ -677,7 +682,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,
|
||||
mLazyDaemon, token, requestId, receiver, operationId, restricted,
|
||||
options, cookie, false /* requireConfirmation */,
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, isStrongBiometric, mLockoutTracker,
|
||||
mUsageStats, allowBackgroundAuthentication,
|
||||
Utils.getCurrentStrength(mSensorId));
|
||||
@@ -713,7 +719,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
new ClientMonitorCallbackConverter(receiver), faceId, userId, opPackageName,
|
||||
FaceUtils.getLegacyInstance(mSensorId), mSensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_REMOVE,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext, mAuthenticatorIds);
|
||||
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
|
||||
});
|
||||
@@ -731,7 +737,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
opPackageName,
|
||||
FaceUtils.getLegacyInstance(mSensorId), mSensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_REMOVE,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext, mAuthenticatorIds);
|
||||
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
|
||||
});
|
||||
@@ -750,7 +756,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
final FaceResetLockoutClient client = new FaceResetLockoutClient(mContext,
|
||||
mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext, hardwareAuthToken);
|
||||
mScheduler.scheduleClientMonitor(client);
|
||||
});
|
||||
@@ -821,7 +827,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
final FaceInternalCleanupClient client = new FaceInternalCleanupClient(mContext,
|
||||
mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_ENUMERATE,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
FaceUtils.getLegacyInstance(mSensorId), mAuthenticatorIds);
|
||||
mScheduler.scheduleClientMonitor(client, new ClientMonitorCompositeCallback(callback,
|
||||
@@ -953,7 +959,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
final FaceUpdateActiveUserClient client = new FaceUpdateActiveUserClient(mContext,
|
||||
mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext, hasEnrolled, mAuthenticatorIds);
|
||||
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
|
||||
@Override
|
||||
@@ -968,9 +974,10 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
});
|
||||
}
|
||||
|
||||
private BiometricLogger createLogger(int statsAction, int statsClient) {
|
||||
private BiometricLogger createLogger(int statsAction, int statsClient,
|
||||
AuthenticationStatsCollector authenticationStatsCollector) {
|
||||
return new BiometricLogger(mContext, BiometricsProtoEnums.MODALITY_FACE,
|
||||
statsAction, statsClient);
|
||||
statsAction, statsClient, authenticationStatsCollector);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -57,6 +57,7 @@ import android.util.Slog;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.biometrics.AuthenticationStatsCollector;
|
||||
import com.android.server.biometrics.Utils;
|
||||
import com.android.server.biometrics.log.BiometricContext;
|
||||
import com.android.server.biometrics.log.BiometricLogger;
|
||||
@@ -122,6 +123,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
|
||||
@Nullable private ISidefpsController mSidefpsController;
|
||||
private AuthSessionCoordinator mAuthSessionCoordinator;
|
||||
@NonNull private final AuthenticationStatsCollector mAuthenticationStatsCollector;
|
||||
|
||||
private final class BiometricTaskStackListener extends TaskStackListener {
|
||||
@Override
|
||||
@@ -181,6 +183,9 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator();
|
||||
mDaemon = daemon;
|
||||
|
||||
mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
|
||||
BiometricsProtoEnums.MODALITY_FINGERPRINT);
|
||||
|
||||
final List<SensorLocationInternal> workaroundLocations = getWorkaroundSensorProps(context);
|
||||
|
||||
for (SensorProps prop : props) {
|
||||
@@ -338,7 +343,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mFingerprintSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
mFingerprintSensors.get(sensorId).getAuthenticatorIds());
|
||||
scheduleForSensor(sensorId, client);
|
||||
@@ -363,7 +369,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mContext, mFingerprintSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, hardwareAuthToken,
|
||||
mFingerprintSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher,
|
||||
Utils.getCurrentStrength(sensorId));
|
||||
@@ -380,7 +387,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mFingerprintSensors.get(sensorId).getLazySession(), token,
|
||||
new ClientMonitorCallbackConverter(receiver), userId, opPackageName,
|
||||
sensorId, createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
@@ -395,7 +402,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mFingerprintSensors.get(sensorId).getLazySession(), token,
|
||||
userId, opPackageName, sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, challenge);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
@@ -415,7 +423,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
|
||||
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_ENROLL,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
mFingerprintSensors.get(sensorId).getSensorProperties(),
|
||||
mUdfpsOverlayController, mSidefpsController,
|
||||
@@ -455,7 +463,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
|
||||
mFingerprintSensors.get(sensorId).getLazySession(), token, id, callback,
|
||||
options,
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, mUdfpsOverlayController, isStrongBiometric);
|
||||
scheduleForSensor(sensorId, client, mBiometricStateCallback);
|
||||
});
|
||||
@@ -477,7 +486,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mContext, mFingerprintSensors.get(sensorId).getLazySession(), token, requestId,
|
||||
callback, operationId, restricted, options, cookie,
|
||||
false /* requireConfirmation */,
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, isStrongBiometric,
|
||||
mTaskStackListener, mFingerprintSensors.get(sensorId).getLockoutCache(),
|
||||
mUdfpsOverlayController, mSidefpsController,
|
||||
@@ -566,7 +576,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
new ClientMonitorCallbackConverter(receiver), fingerprintIds, userId,
|
||||
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_REMOVE,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
mFingerprintSensors.get(sensorId).getAuthenticatorIds());
|
||||
scheduleForSensor(sensorId, client, mBiometricStateCallback);
|
||||
@@ -588,7 +599,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mFingerprintSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_ENUMERATE,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
FingerprintUtils.getInstance(sensorId),
|
||||
mFingerprintSensors.get(sensorId).getAuthenticatorIds());
|
||||
@@ -600,9 +612,10 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
});
|
||||
}
|
||||
|
||||
private BiometricLogger createLogger(int statsAction, int statsClient) {
|
||||
private BiometricLogger createLogger(int statsAction, int statsClient,
|
||||
AuthenticationStatsCollector authenticationStatsCollector) {
|
||||
return new BiometricLogger(mContext, BiometricsProtoEnums.MODALITY_FINGERPRINT,
|
||||
statsAction, statsClient);
|
||||
statsAction, statsClient, authenticationStatsCollector);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -635,7 +648,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
new FingerprintInvalidationClient(mContext,
|
||||
mFingerprintSensors.get(sensorId).getLazySession(), userId, sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
mFingerprintSensors.get(sensorId).getAuthenticatorIds(), callback);
|
||||
scheduleForSensor(sensorId, client);
|
||||
|
||||
@@ -52,6 +52,7 @@ import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.server.biometrics.AuthenticationStatsCollector;
|
||||
import com.android.server.biometrics.SensorServiceStateProto;
|
||||
import com.android.server.biometrics.SensorStateProto;
|
||||
import com.android.server.biometrics.UserStateProto;
|
||||
@@ -123,6 +124,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
|
||||
@Nullable private ISidefpsController mSidefpsController;
|
||||
@NonNull private final BiometricContext mBiometricContext;
|
||||
@NonNull private final AuthenticationStatsCollector mAuthenticationStatsCollector;
|
||||
// for requests that do not use biometric prompt
|
||||
@NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
|
||||
private int mCurrentUserId = UserHandle.USER_NULL;
|
||||
@@ -351,6 +353,9 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
mCurrentUserId = UserHandle.USER_NULL;
|
||||
});
|
||||
|
||||
mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
|
||||
BiometricsProtoEnums.MODALITY_FINGERPRINT);
|
||||
|
||||
try {
|
||||
ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
|
||||
} catch (RemoteException e) {
|
||||
@@ -497,7 +502,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
new FingerprintUpdateActiveUserClient(mContext, mLazyDaemon, targetUserId,
|
||||
mContext.getOpPackageName(), mSensorProperties.sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
this::getCurrentUser, hasEnrolled, mAuthenticatorIds, force);
|
||||
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
|
||||
@@ -544,7 +550,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
final FingerprintResetLockoutClient client = new FingerprintResetLockoutClient(mContext,
|
||||
userId, mContext.getOpPackageName(), sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, mLockoutTracker);
|
||||
mScheduler.scheduleClientMonitor(client);
|
||||
});
|
||||
@@ -559,7 +566,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
new ClientMonitorCallbackConverter(receiver), userId, opPackageName,
|
||||
mSensorProperties.sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext);
|
||||
mScheduler.scheduleClientMonitor(client);
|
||||
});
|
||||
@@ -573,7 +581,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
mContext, mLazyDaemon, token, userId, opPackageName,
|
||||
mSensorProperties.sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext);
|
||||
mScheduler.scheduleClientMonitor(client);
|
||||
});
|
||||
@@ -594,7 +603,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
FingerprintUtils.getLegacyInstance(mSensorId), ENROLL_TIMEOUT_SEC,
|
||||
mSensorProperties.sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_ENROLL,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext, mUdfpsOverlayController, mSidefpsController, enrollReason);
|
||||
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
|
||||
@Override
|
||||
@@ -639,7 +648,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId);
|
||||
final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
|
||||
mLazyDaemon, token, id, listener, options,
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, mUdfpsOverlayController, isStrongBiometric);
|
||||
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
|
||||
});
|
||||
@@ -660,7 +670,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
|
||||
mContext, mLazyDaemon, token, requestId, listener, operationId,
|
||||
restricted, options, cookie, false /* requireConfirmation */,
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
|
||||
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient,
|
||||
mAuthenticationStatsCollector),
|
||||
mBiometricContext, isStrongBiometric,
|
||||
mTaskStackListener, mLockoutTracker,
|
||||
mUdfpsOverlayController, mSidefpsController,
|
||||
@@ -706,7 +717,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
userId, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId),
|
||||
mSensorProperties.sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_REMOVE,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext, mAuthenticatorIds);
|
||||
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
|
||||
});
|
||||
@@ -726,7 +737,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
FingerprintUtils.getLegacyInstance(mSensorId),
|
||||
mSensorProperties.sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_REMOVE,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext, mAuthenticatorIds);
|
||||
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
|
||||
});
|
||||
@@ -741,7 +752,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
mContext, mLazyDaemon, userId, mContext.getOpPackageName(),
|
||||
mSensorProperties.sensorId,
|
||||
createLogger(BiometricsProtoEnums.ACTION_ENUMERATE,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN),
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
|
||||
mBiometricContext,
|
||||
FingerprintUtils.getLegacyInstance(mSensorId), mAuthenticatorIds);
|
||||
mScheduler.scheduleClientMonitor(client, callback);
|
||||
@@ -762,9 +773,10 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
mBiometricStateCallback));
|
||||
}
|
||||
|
||||
private BiometricLogger createLogger(int statsAction, int statsClient) {
|
||||
private BiometricLogger createLogger(int statsAction, int statsClient,
|
||||
AuthenticationStatsCollector authenticationStatsCollector) {
|
||||
return new BiometricLogger(mContext, BiometricsProtoEnums.MODALITY_FINGERPRINT,
|
||||
statsAction, statsClient);
|
||||
statsAction, statsClient, authenticationStatsCollector);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
public class AuthenticationStatsCollectorTest {
|
||||
|
||||
private AuthenticationStatsCollector mAuthenticationStatsCollector;
|
||||
private static final float FRR_THRESHOLD = 0.2f;
|
||||
private static final int USER_ID_1 = 1;
|
||||
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private Resources mResources;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getFraction(R.fraction.config_biometricNotificationFrrThreshold, 1, 1))
|
||||
.thenReturn(FRR_THRESHOLD);
|
||||
|
||||
mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
|
||||
0 /* modality */);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void authenticate_authenticationSucceeded_mapShouldBeUpdated() {
|
||||
// Assert that the user doesn't exist in the map initially.
|
||||
assertNull(mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1));
|
||||
|
||||
mAuthenticationStatsCollector.authenticate(USER_ID_1, true /* authenticated*/);
|
||||
|
||||
AuthenticationStats authenticationStats =
|
||||
mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1);
|
||||
assertEquals(USER_ID_1, authenticationStats.getUserId());
|
||||
assertEquals(1, authenticationStats.getTotalAttempts());
|
||||
assertEquals(0, authenticationStats.getRejectedAttempts());
|
||||
assertEquals(0, authenticationStats.getEnrollmentNotifications());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticate_authenticationFailed_mapShouldBeUpdated() {
|
||||
// Assert that the user doesn't exist in the map initially.
|
||||
assertNull(mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1));
|
||||
|
||||
mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated*/);
|
||||
|
||||
AuthenticationStats authenticationStats =
|
||||
mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1);
|
||||
assertEquals(USER_ID_1, authenticationStats.getUserId());
|
||||
assertEquals(1, authenticationStats.getTotalAttempts());
|
||||
assertEquals(1, authenticationStats.getRejectedAttempts());
|
||||
assertEquals(0, authenticationStats.getEnrollmentNotifications());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class AuthenticationStatsTest {
|
||||
|
||||
@Test
|
||||
public void authenticate_statsShouldBeUpdated() {
|
||||
AuthenticationStats authenticationStats =
|
||||
new AuthenticationStats(1 /* userId */ , 0 /* totalAttempts */,
|
||||
0 /* rejectedAttempts */, 0 /* enrollmentNotifications */,
|
||||
0 /* modality */);
|
||||
|
||||
authenticationStats.authenticate(true /* authenticated */);
|
||||
|
||||
assertEquals(authenticationStats.getTotalAttempts(), 1);
|
||||
assertEquals(authenticationStats.getRejectedAttempts(), 0);
|
||||
|
||||
authenticationStats.authenticate(false /* authenticated */);
|
||||
|
||||
assertEquals(authenticationStats.getTotalAttempts(), 2);
|
||||
assertEquals(authenticationStats.getRejectedAttempts(), 1);
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import android.testing.TestableContext;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.server.biometrics.AuthenticationStatsCollector;
|
||||
import com.android.server.biometrics.sensors.BaseClientMonitor;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -65,6 +66,8 @@ public class BiometricLoggerTest {
|
||||
@Mock
|
||||
private BiometricFrameworkStatsLogger mSink;
|
||||
@Mock
|
||||
private AuthenticationStatsCollector mAuthenticationStatsCollector;
|
||||
@Mock
|
||||
private SensorManager mSensorManager;
|
||||
@Mock
|
||||
private BaseClientMonitor mClient;
|
||||
@@ -87,7 +90,8 @@ public class BiometricLoggerTest {
|
||||
}
|
||||
|
||||
private BiometricLogger createLogger(int statsModality, int statsAction, int statsClient) {
|
||||
return new BiometricLogger(statsModality, statsAction, statsClient, mSink, mSensorManager);
|
||||
return new BiometricLogger(statsModality, statsAction, statsClient, mSink,
|
||||
mAuthenticationStatsCollector, mSensorManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.biometrics.common.CommonProps;
|
||||
import android.hardware.biometrics.face.IFace;
|
||||
import android.hardware.biometrics.face.ISession;
|
||||
@@ -39,6 +40,7 @@ import android.platform.test.annotations.Presubmit;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.server.biometrics.log.BiometricContext;
|
||||
import com.android.server.biometrics.sensors.BaseClientMonitor;
|
||||
import com.android.server.biometrics.sensors.BiometricScheduler;
|
||||
@@ -59,11 +61,15 @@ public class FaceProviderTest {
|
||||
|
||||
private static final String TAG = "FaceProviderTest";
|
||||
|
||||
private static final float FRR_THRESHOLD = 0.2f;
|
||||
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private Resources mResources;
|
||||
@Mock
|
||||
private IFace mDaemon;
|
||||
@Mock
|
||||
private BiometricContext mBiometricContext;
|
||||
@@ -86,6 +92,10 @@ public class FaceProviderTest {
|
||||
when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
|
||||
when(mDaemon.createSession(anyInt(), anyInt(), any())).thenReturn(mock(ISession.class));
|
||||
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getFraction(R.fraction.config_biometricNotificationFrrThreshold, 1, 1))
|
||||
.thenReturn(FRR_THRESHOLD);
|
||||
|
||||
final SensorProps sensor1 = new SensorProps();
|
||||
sensor1.commonProps = new CommonProps();
|
||||
sensor1.commonProps.sensorId = 0;
|
||||
|
||||
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.biometrics.ComponentInfoInternal;
|
||||
import android.hardware.biometrics.SensorProperties;
|
||||
import android.hardware.face.FaceSensorProperties;
|
||||
@@ -41,6 +42,7 @@ import android.platform.test.annotations.Presubmit;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.server.biometrics.log.BiometricContext;
|
||||
import com.android.server.biometrics.sensors.BiometricScheduler;
|
||||
import com.android.server.biometrics.sensors.BiometricStateCallback;
|
||||
@@ -65,12 +67,15 @@ public class Face10Test {
|
||||
private static final String TAG = "Face10Test";
|
||||
private static final int SENSOR_ID = 1;
|
||||
private static final int USER_ID = 20;
|
||||
private static final float FRR_THRESHOLD = 0.2f;
|
||||
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private Resources mResources;
|
||||
@Mock
|
||||
private BiometricScheduler mScheduler;
|
||||
@Mock
|
||||
private BiometricContext mBiometricContext;
|
||||
@@ -93,6 +98,10 @@ public class Face10Test {
|
||||
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
|
||||
when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
|
||||
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getFraction(R.fraction.config_biometricNotificationFrrThreshold, 1, 1))
|
||||
.thenReturn(FRR_THRESHOLD);
|
||||
|
||||
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
|
||||
|
||||
final int maxEnrollmentsPerUser = 1;
|
||||
|
||||
Reference in New Issue
Block a user