Merge "Add timeout to all ALS logging." into tm-qpr-dev
This commit is contained in:
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.log;
|
||||||
|
|
||||||
|
import android.annotation.DurationMillisLong;
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorEvent;
|
||||||
|
import android.hardware.SensorEventListener;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.server.biometrics.sensors.BaseClientMonitor;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/** Probe for ambient light. */
|
||||||
|
final class ALSProbe implements Probe {
|
||||||
|
private static final String TAG = "ALSProbe";
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final SensorManager mSensorManager;
|
||||||
|
@Nullable
|
||||||
|
private final Sensor mLightSensor;
|
||||||
|
@NonNull
|
||||||
|
private final Handler mTimer;
|
||||||
|
@DurationMillisLong
|
||||||
|
private long mMaxSubscriptionTime = -1;
|
||||||
|
|
||||||
|
private boolean mEnabled = false;
|
||||||
|
private boolean mDestroyed = false;
|
||||||
|
private volatile float mLastAmbientLux = -1;
|
||||||
|
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a probe with a 1-minute max sampling time.
|
||||||
|
*
|
||||||
|
* @param sensorManager Sensor manager
|
||||||
|
*/
|
||||||
|
ALSProbe(@NonNull SensorManager sensorManager) {
|
||||||
|
this(sensorManager, new Handler(Looper.getMainLooper()),
|
||||||
|
TimeUnit.MINUTES.toMillis(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a probe with a given max sampling time.
|
||||||
|
*
|
||||||
|
* Note: The max time is a workaround for potential scheduler bugs where
|
||||||
|
* {@link BaseClientMonitor#destroy()} is not called due to an abnormal lifecycle. Clients
|
||||||
|
* should ensure that {@link #disable()} and {@link #destroy()} are called appropriately and
|
||||||
|
* avoid relying on this timeout to unsubscribe from the sensor when it is not needed.
|
||||||
|
*
|
||||||
|
* @param sensorManager Sensor manager
|
||||||
|
* @param handler Timeout handler
|
||||||
|
* @param maxTime The max amount of time to subscribe to events. If this time is exceeded
|
||||||
|
* {@link #disable()} will be called and no sampling will occur until {@link
|
||||||
|
* #enable()} is called again.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
ALSProbe(@Nullable SensorManager sensorManager, @NonNull Handler handler,
|
||||||
|
@DurationMillisLong long maxTime) {
|
||||||
|
mSensorManager = sensorManager;
|
||||||
|
mLightSensor = sensorManager != null
|
||||||
|
? sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) : null;
|
||||||
|
mTimer = handler;
|
||||||
|
mMaxSubscriptionTime = maxTime;
|
||||||
|
|
||||||
|
if (mSensorManager == null || mLightSensor == null) {
|
||||||
|
Slog.w(TAG, "No sensor - probe disabled");
|
||||||
|
mDestroyed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void enable() {
|
||||||
|
if (!mDestroyed) {
|
||||||
|
enableLightSensorLoggingLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void disable() {
|
||||||
|
if (!mDestroyed) {
|
||||||
|
disableLightSensorLoggingLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void destroy() {
|
||||||
|
disable();
|
||||||
|
mDestroyed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The most recent lux reading. */
|
||||||
|
public float getCurrentLux() {
|
||||||
|
return mLastAmbientLux;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enableLightSensorLoggingLocked() {
|
||||||
|
if (!mEnabled) {
|
||||||
|
mEnabled = true;
|
||||||
|
mLastAmbientLux = -1;
|
||||||
|
mSensorManager.registerListener(mLightSensorListener, mLightSensor,
|
||||||
|
SensorManager.SENSOR_DELAY_NORMAL);
|
||||||
|
Slog.v(TAG, "Enable ALS: " + mLightSensorListener.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
resetTimerLocked(true /* start */);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disableLightSensorLoggingLocked() {
|
||||||
|
resetTimerLocked(false /* start */);
|
||||||
|
|
||||||
|
if (mEnabled) {
|
||||||
|
mEnabled = false;
|
||||||
|
mLastAmbientLux = -1;
|
||||||
|
mSensorManager.unregisterListener(mLightSensorListener);
|
||||||
|
Slog.v(TAG, "Disable ALS: " + mLightSensorListener.hashCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetTimerLocked(boolean start) {
|
||||||
|
mTimer.removeCallbacksAndMessages(this /* token */);
|
||||||
|
if (start && mMaxSubscriptionTime > 0) {
|
||||||
|
mTimer.postDelayed(this::onTimeout, this /* token */, mMaxSubscriptionTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onTimeout() {
|
||||||
|
Slog.e(TAG, "Max time exceeded for ALS logger - disabling: "
|
||||||
|
+ mLightSensorListener.hashCode());
|
||||||
|
disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,21 +17,15 @@
|
|||||||
package com.android.server.biometrics.log;
|
package com.android.server.biometrics.log;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
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.SensorManager;
|
||||||
import android.hardware.biometrics.BiometricConstants;
|
import android.hardware.biometrics.BiometricConstants;
|
||||||
import android.hardware.biometrics.BiometricsProtoEnums;
|
import android.hardware.biometrics.BiometricsProtoEnums;
|
||||||
import android.hardware.biometrics.common.OperationContext;
|
import android.hardware.biometrics.common.OperationContext;
|
||||||
import android.hardware.face.FaceManager;
|
import android.hardware.face.FaceManager;
|
||||||
import android.hardware.fingerprint.FingerprintManager;
|
import android.hardware.fingerprint.FingerprintManager;
|
||||||
import android.util.Log;
|
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.FrameworkStatsLog;
|
import com.android.internal.util.FrameworkStatsLog;
|
||||||
import com.android.server.biometrics.Utils;
|
import com.android.server.biometrics.Utils;
|
||||||
@@ -43,61 +37,16 @@ public class BiometricLogger {
|
|||||||
|
|
||||||
public static final String TAG = "BiometricLogger";
|
public static final String TAG = "BiometricLogger";
|
||||||
public static final boolean DEBUG = false;
|
public static final boolean DEBUG = false;
|
||||||
private static final Object sLock = new Object();
|
|
||||||
|
|
||||||
@GuardedBy("sLock")
|
|
||||||
private static int sAlsCounter;
|
|
||||||
|
|
||||||
private final int mStatsModality;
|
private final int mStatsModality;
|
||||||
private final int mStatsAction;
|
private final int mStatsAction;
|
||||||
private final int mStatsClient;
|
private final int mStatsClient;
|
||||||
private final BiometricFrameworkStatsLogger mSink;
|
private final BiometricFrameworkStatsLogger mSink;
|
||||||
@NonNull private final SensorManager mSensorManager;
|
@NonNull private final ALSProbe mALSProbe;
|
||||||
|
|
||||||
private long mFirstAcquireTimeMs;
|
private long mFirstAcquireTimeMs;
|
||||||
private boolean mLightSensorEnabled = false;
|
|
||||||
private boolean mShouldLogMetrics = true;
|
private boolean mShouldLogMetrics = true;
|
||||||
|
|
||||||
private class ALSProbe implements Probe {
|
|
||||||
private boolean mDestroyed = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void enable() {
|
|
||||||
if (!mDestroyed) {
|
|
||||||
setLightSensorLoggingEnabled(getAmbientLightSensor(mSensorManager));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void disable() {
|
|
||||||
if (!mDestroyed) {
|
|
||||||
setLightSensorLoggingEnabled(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void destroy() {
|
|
||||||
disable();
|
|
||||||
mDestroyed = 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.
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Get a new logger with all unknown fields (for operations that do not require logs). */
|
/** Get a new logger with all unknown fields (for operations that do not require logs). */
|
||||||
public static BiometricLogger ofUnknown(@NonNull Context context) {
|
public static BiometricLogger ofUnknown(@NonNull Context context) {
|
||||||
return new BiometricLogger(context, BiometricsProtoEnums.MODALITY_UNKNOWN,
|
return new BiometricLogger(context, BiometricsProtoEnums.MODALITY_UNKNOWN,
|
||||||
@@ -105,6 +54,11 @@ public class BiometricLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Creates a new logger for an instance of a biometric operation.
|
||||||
|
*
|
||||||
|
* Do not reuse across operations. Instead, create a new one or use
|
||||||
|
* {@link #swapAction(Context, int)}.
|
||||||
|
*
|
||||||
* @param context system_server context
|
* @param context system_server context
|
||||||
* @param statsModality One of {@link BiometricsProtoEnums} MODALITY_* constants.
|
* @param statsModality One of {@link BiometricsProtoEnums} MODALITY_* constants.
|
||||||
* @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants.
|
* @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants.
|
||||||
@@ -125,7 +79,7 @@ public class BiometricLogger {
|
|||||||
mStatsAction = statsAction;
|
mStatsAction = statsAction;
|
||||||
mStatsClient = statsClient;
|
mStatsClient = statsClient;
|
||||||
mSink = logSink;
|
mSink = logSink;
|
||||||
mSensorManager = sensorManager;
|
mALSProbe = new ALSProbe(sensorManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a new logger with the action replaced with the new action. */
|
/** Creates a new logger with the action replaced with the new action. */
|
||||||
@@ -136,6 +90,7 @@ public class BiometricLogger {
|
|||||||
/** Disable logging metrics and only log critical events, such as system health issues. */
|
/** Disable logging metrics and only log critical events, such as system health issues. */
|
||||||
public void disableMetrics() {
|
public void disableMetrics() {
|
||||||
mShouldLogMetrics = false;
|
mShouldLogMetrics = false;
|
||||||
|
mALSProbe.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@link BiometricsProtoEnums} CLIENT_* constants */
|
/** {@link BiometricsProtoEnums} CLIENT_* constants */
|
||||||
@@ -265,7 +220,7 @@ public class BiometricLogger {
|
|||||||
+ ", RequireConfirmation: " + requireConfirmation
|
+ ", RequireConfirmation: " + requireConfirmation
|
||||||
+ ", State: " + authState
|
+ ", State: " + authState
|
||||||
+ ", Latency: " + latency
|
+ ", Latency: " + latency
|
||||||
+ ", Lux: " + mLastAmbientLux);
|
+ ", Lux: " + mALSProbe.getCurrentLux());
|
||||||
} else {
|
} else {
|
||||||
Slog.v(TAG, "Authentication latency: " + latency);
|
Slog.v(TAG, "Authentication latency: " + latency);
|
||||||
}
|
}
|
||||||
@@ -276,7 +231,7 @@ public class BiometricLogger {
|
|||||||
|
|
||||||
mSink.authenticate(operationContext, mStatsModality, mStatsAction, mStatsClient,
|
mSink.authenticate(operationContext, mStatsModality, mStatsAction, mStatsClient,
|
||||||
Utils.isDebugEnabled(context, targetUserId),
|
Utils.isDebugEnabled(context, targetUserId),
|
||||||
latency, authState, requireConfirmation, targetUserId, mLastAmbientLux);
|
latency, authState, requireConfirmation, targetUserId, mALSProbe.getCurrentLux());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Log enrollment outcome. */
|
/** Log enrollment outcome. */
|
||||||
@@ -290,7 +245,7 @@ public class BiometricLogger {
|
|||||||
+ ", User: " + targetUserId
|
+ ", User: " + targetUserId
|
||||||
+ ", Client: " + mStatsClient
|
+ ", Client: " + mStatsClient
|
||||||
+ ", Latency: " + latency
|
+ ", Latency: " + latency
|
||||||
+ ", Lux: " + mLastAmbientLux
|
+ ", Lux: " + mALSProbe.getCurrentLux()
|
||||||
+ ", Success: " + enrollSuccessful);
|
+ ", Success: " + enrollSuccessful);
|
||||||
} else {
|
} else {
|
||||||
Slog.v(TAG, "Enroll latency: " + latency);
|
Slog.v(TAG, "Enroll latency: " + latency);
|
||||||
@@ -301,7 +256,7 @@ public class BiometricLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mSink.enroll(mStatsModality, mStatsAction, mStatsClient,
|
mSink.enroll(mStatsModality, mStatsAction, mStatsClient,
|
||||||
targetUserId, latency, enrollSuccessful, mLastAmbientLux);
|
targetUserId, latency, enrollSuccessful, mALSProbe.getCurrentLux());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Report unexpected enrollment reported by the HAL. */
|
/** Report unexpected enrollment reported by the HAL. */
|
||||||
@@ -323,7 +278,9 @@ public class BiometricLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a callback to start/stop ALS capture when a client runs.
|
* Get a callback to start/stop ALS capture when the client runs. Do not create
|
||||||
|
* multiple callbacks since there is at most one light sensor (they will all share
|
||||||
|
* a single probe sampling from that sensor).
|
||||||
*
|
*
|
||||||
* If the probe should not run for the entire operation, do not set startWithClient and
|
* If the probe should not run for the entire operation, do not set startWithClient and
|
||||||
* start/stop the problem when needed.
|
* start/stop the problem when needed.
|
||||||
@@ -331,53 +288,7 @@ public class BiometricLogger {
|
|||||||
* @param startWithClient if probe should start automatically when the operation starts.
|
* @param startWithClient if probe should start automatically when the operation starts.
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public CallbackWithProbe<Probe> createALSCallback(boolean startWithClient) {
|
public CallbackWithProbe<Probe> getAmbientLightProbe(boolean startWithClient) {
|
||||||
return new CallbackWithProbe<>(new ALSProbe(), startWithClient);
|
return new CallbackWithProbe<>(mALSProbe, startWithClient);
|
||||||
}
|
|
||||||
|
|
||||||
/** 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;
|
|
||||||
int localAlsCounter;
|
|
||||||
synchronized (sLock) {
|
|
||||||
localAlsCounter = sAlsCounter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (localAlsCounter == 0) {
|
|
||||||
mSensorManager.registerListener(mLightSensorListener, lightSensor,
|
|
||||||
SensorManager.SENSOR_DELAY_NORMAL);
|
|
||||||
} else {
|
|
||||||
Slog.e(TAG, "Ignoring request to subscribe to ALSProbe due to non-zero ALS"
|
|
||||||
+ " counter: " + localAlsCounter);
|
|
||||||
Slog.e(TAG, Log.getStackTraceString(new Throwable()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mLightSensorEnabled = false;
|
|
||||||
mLastAmbientLux = 0;
|
|
||||||
mSensorManager.unregisterListener(mLightSensorListener);
|
|
||||||
int localAlsCounter;
|
|
||||||
synchronized (sLock) {
|
|
||||||
localAlsCounter = --sAlsCounter;
|
|
||||||
}
|
|
||||||
if (localAlsCounter != 0) {
|
|
||||||
Slog.e(TAG, "Non-zero ALS counter after unsubscribing from ALSProbe: "
|
|
||||||
+ localAlsCounter);
|
|
||||||
Slog.e(TAG, Log.getStackTraceString(new Throwable()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
|
|||||||
@Override
|
@Override
|
||||||
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
|
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
|
||||||
return new ClientMonitorCompositeCallback(
|
return new ClientMonitorCompositeCallback(
|
||||||
getLogger().createALSCallback(true /* startWithClient */), callback);
|
getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ public class FaceEnrollClient extends EnrollClient<AidlSession> {
|
|||||||
@Override
|
@Override
|
||||||
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
|
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
|
||||||
return new ClientMonitorCompositeCallback(mPreviewHandleDeleterCallback,
|
return new ClientMonitorCompositeCallback(mPreviewHandleDeleterCallback,
|
||||||
getLogger().createALSCallback(true /* startWithClient */), callback);
|
getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
|
|||||||
@Override
|
@Override
|
||||||
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
|
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
|
||||||
return new ClientMonitorCompositeCallback(
|
return new ClientMonitorCompositeCallback(
|
||||||
getLogger().createALSCallback(true /* startWithClient */), callback);
|
getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
|
|||||||
@Override
|
@Override
|
||||||
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
|
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
|
||||||
return new ClientMonitorCompositeCallback(
|
return new ClientMonitorCompositeCallback(
|
||||||
getLogger().createALSCallback(true /* startWithClient */), callback);
|
getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
|
|||||||
mLockoutCache = lockoutCache;
|
mLockoutCache = lockoutCache;
|
||||||
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
|
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
|
||||||
mSensorProps = sensorProps;
|
mSensorProps = sensorProps;
|
||||||
mALSProbeCallback = getLogger().createALSCallback(false /* startWithClient */);
|
mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
|
||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
|
|
||||||
mWaitForAuthKeyguard =
|
mWaitForAuthKeyguard =
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps
|
|||||||
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
|
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
|
||||||
mMaxTemplatesPerUser = maxTemplatesPerUser;
|
mMaxTemplatesPerUser = maxTemplatesPerUser;
|
||||||
|
|
||||||
mALSProbeCallback = getLogger().createALSCallback(false /* startWithClient */);
|
mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
|
||||||
|
|
||||||
mEnrollReason = enrollReason;
|
mEnrollReason = enrollReason;
|
||||||
if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
|
if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
|
|||||||
mLockoutFrameworkImpl = lockoutTracker;
|
mLockoutFrameworkImpl = lockoutTracker;
|
||||||
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
|
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
|
||||||
mSensorProps = sensorProps;
|
mSensorProps = sensorProps;
|
||||||
mALSProbeCallback = getLogger().createALSCallback(false /* startWithClient */);
|
mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
|
|||||||
@Override
|
@Override
|
||||||
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
|
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
|
||||||
return new ClientMonitorCompositeCallback(
|
return new ClientMonitorCompositeCallback(
|
||||||
getLogger().createALSCallback(true /* startWithClient */), callback);
|
getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.log;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.anyInt;
|
||||||
|
import static org.mockito.Mockito.eq;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.reset;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorEvent;
|
||||||
|
import android.hardware.SensorEventListener;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
|
import android.hardware.input.InputSensorInfo;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
import android.testing.AndroidTestingRunner;
|
||||||
|
import android.testing.TestableLooper;
|
||||||
|
import android.testing.TestableLooper.RunWithLooper;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnit;
|
||||||
|
import org.mockito.junit.MockitoRule;
|
||||||
|
|
||||||
|
@Presubmit
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner.class)
|
||||||
|
@RunWithLooper
|
||||||
|
public class ALSProbeTest {
|
||||||
|
|
||||||
|
private static final long TIMEOUT_MS = 1000;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final MockitoRule mockito = MockitoJUnit.rule();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private SensorManager mSensorManager;
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor;
|
||||||
|
|
||||||
|
private TestableLooper mLooper;
|
||||||
|
private Sensor mLightSensor = new Sensor(
|
||||||
|
new InputSensorInfo("", "", 0, 0, Sensor.TYPE_LIGHT, 0, 0, 0, 0, 0, 0,
|
||||||
|
"", "", 0, 0, 0));
|
||||||
|
|
||||||
|
private ALSProbe mProbe;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
mLooper = TestableLooper.get(this);
|
||||||
|
when(mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)).thenReturn(mLightSensor);
|
||||||
|
mProbe = new ALSProbe(mSensorManager, new Handler(mLooper.getLooper()), TIMEOUT_MS - 1);
|
||||||
|
reset(mSensorManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnable() {
|
||||||
|
final float value = 2.0f;
|
||||||
|
mProbe.enable();
|
||||||
|
verify(mSensorManager).registerListener(
|
||||||
|
mSensorEventListenerCaptor.capture(), any(), anyInt());
|
||||||
|
|
||||||
|
mSensorEventListenerCaptor.getValue().onSensorChanged(
|
||||||
|
new SensorEvent(mLightSensor, 1, 1, new float[]{4.0f}));
|
||||||
|
mSensorEventListenerCaptor.getValue().onSensorChanged(
|
||||||
|
new SensorEvent(mLightSensor, 1, 2, new float[]{value}));
|
||||||
|
|
||||||
|
assertThat(mProbe.getCurrentLux()).isEqualTo(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableOnlyOnce() {
|
||||||
|
mProbe.enable();
|
||||||
|
mProbe.enable();
|
||||||
|
|
||||||
|
verify(mSensorManager).registerListener(any(), any(), anyInt());
|
||||||
|
verifyNoMoreInteractions(mSensorManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisable() {
|
||||||
|
mProbe.enable();
|
||||||
|
verify(mSensorManager).registerListener(
|
||||||
|
mSensorEventListenerCaptor.capture(), any(), anyInt());
|
||||||
|
mProbe.disable();
|
||||||
|
|
||||||
|
verify(mSensorManager).unregisterListener(eq(mSensorEventListenerCaptor.getValue()));
|
||||||
|
verifyNoMoreInteractions(mSensorManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDestroy() {
|
||||||
|
mProbe.destroy();
|
||||||
|
mProbe.enable();
|
||||||
|
|
||||||
|
verify(mSensorManager, never()).registerListener(any(), any(), anyInt());
|
||||||
|
verifyNoMoreInteractions(mSensorManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisabledReportsNegativeValue() {
|
||||||
|
assertThat(mProbe.getCurrentLux()).isLessThan(0f);
|
||||||
|
|
||||||
|
mProbe.enable();
|
||||||
|
verify(mSensorManager).registerListener(
|
||||||
|
mSensorEventListenerCaptor.capture(), any(), anyInt());
|
||||||
|
mSensorEventListenerCaptor.getValue().onSensorChanged(
|
||||||
|
new SensorEvent(mLightSensor, 1, 1, new float[]{4.0f}));
|
||||||
|
mProbe.disable();
|
||||||
|
|
||||||
|
assertThat(mProbe.getCurrentLux()).isLessThan(0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWatchDog() {
|
||||||
|
mProbe.enable();
|
||||||
|
verify(mSensorManager).registerListener(
|
||||||
|
mSensorEventListenerCaptor.capture(), any(), anyInt());
|
||||||
|
mSensorEventListenerCaptor.getValue().onSensorChanged(
|
||||||
|
new SensorEvent(mLightSensor, 1, 1, new float[]{4.0f}));
|
||||||
|
moveTimeBy(TIMEOUT_MS);
|
||||||
|
|
||||||
|
verify(mSensorManager).unregisterListener(eq(mSensorEventListenerCaptor.getValue()));
|
||||||
|
verifyNoMoreInteractions(mSensorManager);
|
||||||
|
assertThat(mProbe.getCurrentLux()).isLessThan(0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableExtendsWatchDog() {
|
||||||
|
mProbe.enable();
|
||||||
|
verify(mSensorManager).registerListener(any(), any(), anyInt());
|
||||||
|
|
||||||
|
moveTimeBy(TIMEOUT_MS / 2);
|
||||||
|
verify(mSensorManager, never()).unregisterListener(any(SensorEventListener.class));
|
||||||
|
|
||||||
|
mProbe.enable();
|
||||||
|
moveTimeBy(TIMEOUT_MS);
|
||||||
|
|
||||||
|
verify(mSensorManager).unregisterListener(any(SensorEventListener.class));
|
||||||
|
verifyNoMoreInteractions(mSensorManager);
|
||||||
|
assertThat(mProbe.getCurrentLux()).isLessThan(0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveTimeBy(long millis) {
|
||||||
|
mLooper.moveTimeForward(millis);
|
||||||
|
mLooper.processAllMessages();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -232,7 +232,7 @@ public class BiometricLoggerTest {
|
|||||||
public void testALSCallback() {
|
public void testALSCallback() {
|
||||||
mLogger = createLogger();
|
mLogger = createLogger();
|
||||||
final CallbackWithProbe<Probe> callback =
|
final CallbackWithProbe<Probe> callback =
|
||||||
mLogger.createALSCallback(true /* startWithClient */);
|
mLogger.getAmbientLightProbe(true /* startWithClient */);
|
||||||
|
|
||||||
callback.onClientStarted(mClient);
|
callback.onClientStarted(mClient);
|
||||||
verify(mSensorManager).registerListener(any(), any(), anyInt());
|
verify(mSensorManager).registerListener(any(), any(), anyInt());
|
||||||
@@ -241,11 +241,38 @@ public class BiometricLoggerTest {
|
|||||||
verify(mSensorManager).unregisterListener(any(SensorEventListener.class));
|
verify(mSensorManager).unregisterListener(any(SensorEventListener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testALSCallbackWhenLogsDisabled() {
|
||||||
|
mLogger = createLogger();
|
||||||
|
mLogger.disableMetrics();
|
||||||
|
final CallbackWithProbe<Probe> callback =
|
||||||
|
mLogger.getAmbientLightProbe(true /* startWithClient */);
|
||||||
|
|
||||||
|
callback.onClientStarted(mClient);
|
||||||
|
verify(mSensorManager, never()).registerListener(any(), any(), anyInt());
|
||||||
|
|
||||||
|
callback.onClientFinished(mClient, true /* success */);
|
||||||
|
verify(mSensorManager, never()).unregisterListener(any(SensorEventListener.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testALSCallbackWhenDisabledAfterStarting() {
|
||||||
|
mLogger = createLogger();
|
||||||
|
final CallbackWithProbe<Probe> callback =
|
||||||
|
mLogger.getAmbientLightProbe(true /* startWithClient */);
|
||||||
|
|
||||||
|
callback.onClientStarted(mClient);
|
||||||
|
verify(mSensorManager).registerListener(any(), any(), anyInt());
|
||||||
|
|
||||||
|
mLogger.disableMetrics();
|
||||||
|
verify(mSensorManager).unregisterListener(any(SensorEventListener.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testALSCallbackDoesNotStart() {
|
public void testALSCallbackDoesNotStart() {
|
||||||
mLogger = createLogger();
|
mLogger = createLogger();
|
||||||
final CallbackWithProbe<Probe> callback =
|
final CallbackWithProbe<Probe> callback =
|
||||||
mLogger.createALSCallback(false /* startWithClient */);
|
mLogger.getAmbientLightProbe(false /* startWithClient */);
|
||||||
|
|
||||||
callback.onClientStarted(mClient);
|
callback.onClientStarted(mClient);
|
||||||
callback.onClientFinished(mClient, true /* success */);
|
callback.onClientFinished(mClient, true /* success */);
|
||||||
@@ -256,7 +283,7 @@ public class BiometricLoggerTest {
|
|||||||
public void testALSCallbackDestroyed() {
|
public void testALSCallbackDestroyed() {
|
||||||
mLogger = createLogger();
|
mLogger = createLogger();
|
||||||
final CallbackWithProbe<Probe> callback =
|
final CallbackWithProbe<Probe> callback =
|
||||||
mLogger.createALSCallback(true /* startWithClient */);
|
mLogger.getAmbientLightProbe(true /* startWithClient */);
|
||||||
|
|
||||||
callback.onClientStarted(mClient);
|
callback.onClientStarted(mClient);
|
||||||
callback.onClientFinished(mClient, false /* success */);
|
callback.onClientFinished(mClient, false /* success */);
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ public class FingerprintAuthenticationClientTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
mContext.addMockSystemService(BiometricManager.class, mBiometricManager);
|
mContext.addMockSystemService(BiometricManager.class, mBiometricManager);
|
||||||
when(mBiometricLogger.createALSCallback(anyBoolean())).thenAnswer(i ->
|
when(mBiometricLogger.getAmbientLightProbe(anyBoolean())).thenAnswer(i ->
|
||||||
new CallbackWithProbe<>(mLuxProbe, i.getArgument(0)));
|
new CallbackWithProbe<>(mLuxProbe, i.getArgument(0)));
|
||||||
when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
|
when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
|
||||||
i -> i.getArgument(0));
|
i -> i.getArgument(0));
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ public class FingerprintEnrollClientTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
when(mBiometricLogger.createALSCallback(anyBoolean())).thenAnswer(i ->
|
when(mBiometricLogger.getAmbientLightProbe(anyBoolean())).thenAnswer(i ->
|
||||||
new CallbackWithProbe<>(mLuxProbe, i.getArgument(0)));
|
new CallbackWithProbe<>(mLuxProbe, i.getArgument(0)));
|
||||||
when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
|
when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
|
||||||
i -> i.getArgument(0));
|
i -> i.getArgument(0));
|
||||||
|
|||||||
Reference in New Issue
Block a user