Merge "Add snapshot of ambient light value to log during enrollment and authentication operations." into sc-dev

This commit is contained in:
Joe Bolinger
2021-06-14 18:39:18 +00:00
committed by Android (Google) Code Review
11 changed files with 177 additions and 21 deletions

View File

@@ -679,7 +679,8 @@ public final class AuthSession implements IBinder.DeathRecipient {
FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED, FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED,
latency, latency,
mDebugEnabled, mDebugEnabled,
-1 /* sensorId */); -1 /* sensorId */,
-1f /* ambientLightLux */);
} else { } else {
final long latency = System.currentTimeMillis() - mStartTimeMs; final long latency = System.currentTimeMillis() - mStartTimeMs;

View File

@@ -69,6 +69,31 @@ public abstract class BaseClientMonitor extends LoggableMonitor
} }
} }
/** Holder for wrapping multiple handlers into a single Callback. */
protected static class CompositeCallback implements Callback {
@NonNull
private final Callback[] mCallbacks;
public CompositeCallback(@NonNull Callback... callbacks) {
mCallbacks = callbacks;
}
@Override
public final void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
for (int i = 0; i < mCallbacks.length; i++) {
mCallbacks[i].onClientStarted(clientMonitor);
}
}
@Override
public final void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
for (int i = mCallbacks.length - 1; i >= 0; i--) {
mCallbacks[i].onClientFinished(clientMonitor, success);
}
}
}
private final int mSequentialId; private final int mSequentialId;
@NonNull private final Context mContext; @NonNull private final Context mContext;
private final int mTargetUserId; private final int mTargetUserId;
@@ -125,7 +150,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor
@Nullable IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId, @Nullable IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int cookie, int sensorId, int statsModality, int statsAction, @NonNull String owner, int cookie, int sensorId, int statsModality, int statsAction,
int statsClient) { int statsClient) {
super(statsModality, statsAction, statsClient); super(context, statsModality, statsAction, statsClient);
mSequentialId = sCount++; mSequentialId = sCount++;
mContext = context; mContext = context;
mToken = token; mToken = token;
@@ -153,10 +178,19 @@ public abstract class BaseClientMonitor extends LoggableMonitor
* @param callback invoked when the operation is complete (succeeds, fails, etc) * @param callback invoked when the operation is complete (succeeds, fails, etc)
*/ */
public void start(@NonNull Callback callback) { public void start(@NonNull Callback callback) {
mCallback = callback; mCallback = wrapCallbackForStart(callback);
mCallback.onClientStarted(this); mCallback.onClientStarted(this);
} }
/**
* Called during start to provide subclasses a hook for decorating the callback.
*
* Returns the original callback unless overridden.
*/
@NonNull
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
return callback;
}
public boolean isAlreadyDone() { public boolean isAlreadyDone() {
return mAlreadyDone; return mAlreadyDone;

View File

@@ -16,7 +16,13 @@
package com.android.server.biometrics.sensors; package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.face.FaceManager; import android.hardware.face.FaceManager;
@@ -37,9 +43,41 @@ public abstract class LoggableMonitor {
final int mStatsModality; final int mStatsModality;
private final int mStatsAction; private final int mStatsAction;
private final int mStatsClient; private final int mStatsClient;
@NonNull private final SensorManager mSensorManager;
private long mFirstAcquireTimeMs; private long mFirstAcquireTimeMs;
private boolean mLightSensorEnabled = false;
private boolean mShouldLogMetrics = true; private boolean mShouldLogMetrics = true;
// report only the most recent value
// consider com.android.server.display.utils.AmbientFilter or similar if need arises
private volatile float mLastAmbientLux = 0;
private final SensorEventListener mLightSensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
mLastAmbientLux = event.values[0];
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Not used.
}
};
/**
* @param context system_server context
* @param statsModality One of {@link BiometricsProtoEnums} MODALITY_* constants.
* @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants.
* @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants.
*/
public LoggableMonitor(@NonNull Context context, int statsModality, int statsAction,
int statsClient) {
mStatsModality = statsModality;
mStatsAction = statsAction;
mStatsClient = statsClient;
mSensorManager = context.getSystemService(SensorManager.class);
}
/** /**
* Only valid for AuthenticationClient. * Only valid for AuthenticationClient.
* @return true if the client is authenticating for a crypto operation. * @return true if the client is authenticating for a crypto operation.
@@ -48,17 +86,6 @@ public abstract class LoggableMonitor {
return false; return false;
} }
/**
* @param statsModality One of {@link BiometricsProtoEnums} MODALITY_* constants.
* @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants.
* @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants.
*/
public LoggableMonitor(int statsModality, int statsAction, int statsClient) {
mStatsModality = statsModality;
mStatsAction = statsAction;
mStatsClient = statsClient;
}
protected void setShouldLog(boolean shouldLog) { protected void setShouldLog(boolean shouldLog) {
mShouldLogMetrics = shouldLog; mShouldLogMetrics = shouldLog;
} }
@@ -131,7 +158,6 @@ public abstract class LoggableMonitor {
} }
protected final void logOnError(Context context, int error, int vendorCode, int targetUserId) { protected final void logOnError(Context context, int error, int vendorCode, int targetUserId) {
if (!mShouldLogMetrics) { if (!mShouldLogMetrics) {
return; return;
} }
@@ -199,7 +225,8 @@ public abstract class LoggableMonitor {
+ ", Client: " + mStatsClient + ", Client: " + mStatsClient
+ ", RequireConfirmation: " + requireConfirmation + ", RequireConfirmation: " + requireConfirmation
+ ", State: " + authState + ", State: " + authState
+ ", Latency: " + latency); + ", Latency: " + latency
+ ", Lux: " + mLastAmbientLux);
} else { } else {
Slog.v(TAG, "Authentication latency: " + latency); Slog.v(TAG, "Authentication latency: " + latency);
} }
@@ -217,7 +244,8 @@ public abstract class LoggableMonitor {
authState, authState,
sanitizeLatency(latency), sanitizeLatency(latency),
Utils.isDebugEnabled(context, targetUserId), Utils.isDebugEnabled(context, targetUserId),
-1 /* sensorId */); -1 /* sensorId */,
mLastAmbientLux /* ambientLightLux */);
} }
protected final void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) { protected final void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) {
@@ -230,6 +258,7 @@ public abstract class LoggableMonitor {
+ ", User: " + targetUserId + ", User: " + targetUserId
+ ", Client: " + mStatsClient + ", Client: " + mStatsClient
+ ", Latency: " + latency + ", Latency: " + latency
+ ", Lux: " + mLastAmbientLux
+ ", Success: " + enrollSuccessful); + ", Success: " + enrollSuccessful);
} else { } else {
Slog.v(TAG, "Enroll latency: " + latency); Slog.v(TAG, "Enroll latency: " + latency);
@@ -244,7 +273,8 @@ public abstract class LoggableMonitor {
targetUserId, targetUserId,
sanitizeLatency(latency), sanitizeLatency(latency),
enrollSuccessful, enrollSuccessful,
-1 /* sensorId */); -1, /* sensorId */
mLastAmbientLux /* ambientLightLux */);
} }
private long sanitizeLatency(long latency) { private long sanitizeLatency(long latency) {
@@ -255,4 +285,46 @@ public abstract class LoggableMonitor {
return latency; return latency;
} }
/** Get a callback to start/stop ALS capture when client runs. */
@NonNull
protected BaseClientMonitor.Callback createALSCallback() {
return new BaseClientMonitor.Callback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
setLightSensorLoggingEnabled(getAmbientLightSensor(mSensorManager));
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
setLightSensorLoggingEnabled(null);
}
};
}
/** The sensor to use for ALS logging. */
@Nullable
protected Sensor getAmbientLightSensor(@NonNull SensorManager sensorManager) {
return mShouldLogMetrics ? sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) : null;
}
private void setLightSensorLoggingEnabled(@Nullable Sensor lightSensor) {
if (DEBUG) {
Slog.v(TAG, "capturing ambient light using: "
+ (lightSensor != null ? lightSensor : "[disabled]"));
}
if (lightSensor != null) {
if (!mLightSensorEnabled) {
mLightSensorEnabled = true;
mLastAmbientLux = 0;
mSensorManager.registerListener(mLightSensorListener, lightSensor,
SensorManager.SENSOR_DELAY_NORMAL);
}
} else {
mLightSensorEnabled = false;
mLastAmbientLux = 0;
mSensorManager.unregisterListener(mLightSensorListener);
}
}
} }

View File

@@ -99,6 +99,12 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
"face_custom_success_error", 0) == 1; "face_custom_success_error", 0) == 1;
} }
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
return new CompositeCallback(createALSCallback(), callback);
}
@Override @Override
protected void startHalOperation() { protected void startHalOperation() {
try { try {
@@ -229,7 +235,8 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
} }
} }
@Override public void onLockoutTimed(long durationMillis) { @Override
public void onLockoutTimed(long durationMillis) {
mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED); mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED);
// Lockout metrics are logged as an error code. // Lockout metrics are logged as an error code.
final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT; final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT;
@@ -242,7 +249,8 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
} }
} }
@Override public void onLockoutPermanent() { @Override
public void onLockoutPermanent() {
mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT); mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT);
// Lockout metrics are logged as an error code. // Lockout metrics are logged as an error code.
final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT; final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT;

View File

@@ -95,6 +95,12 @@ public class FaceEnrollClient extends EnrollClient<ISession> {
ReEnrollNotificationUtils.cancelNotification(getContext()); ReEnrollNotificationUtils.cancelNotification(getContext());
} }
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
return new CompositeCallback(createALSCallback(), callback);
}
@Override @Override
public void destroy() { public void destroy() {
try { try {

View File

@@ -88,6 +88,12 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
"face_custom_success_error", 0) == 1; "face_custom_success_error", 0) == 1;
} }
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
return new CompositeCallback(createALSCallback(), callback);
}
@Override @Override
protected void startHalOperation() { protected void startHalOperation() {
try { try {
@@ -186,7 +192,6 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
@Override @Override
public void onAcquired(int acquireInfo, int vendorCode) { public void onAcquired(int acquireInfo, int vendorCode) {
mLastAcquire = acquireInfo; mLastAcquire = acquireInfo;
if (acquireInfo == FaceManager.FACE_ACQUIRED_RECALIBRATE) { if (acquireInfo == FaceManager.FACE_ACQUIRED_RECALIBRATE) {

View File

@@ -68,6 +68,12 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
.getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist); .getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist);
} }
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
return new CompositeCallback(createALSCallback(), callback);
}
@Override @Override
protected boolean hasReachedEnrollmentLimit() { protected boolean hasReachedEnrollmentLimit() {
final int limit = getContext().getResources().getInteger( final int limit = getContext().getResources().getInteger(

View File

@@ -70,6 +70,12 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
mUdfpsOverlayController = udfpsOverlayController; mUdfpsOverlayController = udfpsOverlayController;
} }
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
return new CompositeCallback(createALSCallback(), callback);
}
@Override @Override
public void onAuthenticated(BiometricAuthenticator.Identifier identifier, public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) { boolean authenticated, ArrayList<Byte> token) {

View File

@@ -79,6 +79,12 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps {
} }
} }
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
return new CompositeCallback(createALSCallback(), callback);
}
@Override @Override
public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) { public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) {
super.onEnrollResult(identifier, remaining); super.onEnrollResult(identifier, remaining);

View File

@@ -69,6 +69,12 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
mUdfpsOverlayController = udfpsOverlayController; mUdfpsOverlayController = udfpsOverlayController;
} }
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
return new CompositeCallback(createALSCallback(), callback);
}
@Override @Override
public void onAuthenticated(BiometricAuthenticator.Identifier identifier, public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) { boolean authenticated, ArrayList<Byte> token) {

View File

@@ -72,6 +72,12 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
} }
} }
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
return new CompositeCallback(createALSCallback(), callback);
}
@Override @Override
protected boolean hasReachedEnrollmentLimit() { protected boolean hasReachedEnrollmentLimit() {
final int limit = getContext().getResources().getInteger( final int limit = getContext().getResources().getInteger(