summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Joe Bolinger <jbolinger@google.com> 2022-08-29 19:57:25 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2022-08-29 19:57:25 +0000
commitbb1fe494eedad6c6785ccd960377f80dc0948f9c (patch)
tree393b26556b9b4f3cbe7c7327968d01fae7f6b91f
parentc861151f1af7ed6ffa3ca653d216d70e040822fb (diff)
parent15be0582446e6333a6ddefa6c64ec0fd4ca6060e (diff)
Merge "Add timeout to all ALS logging." into tm-qpr-dev am: 15be058244
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19745492 Change-Id: I173319ab34f49b084332675f6bc7fdd6878ab7e1 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--services/core/java/com/android/server/biometrics/log/ALSProbe.java163
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricLogger.java123
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/log/ALSProbeTest.java176
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java33
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java2
14 files changed, 396 insertions, 119 deletions
diff --git a/services/core/java/com/android/server/biometrics/log/ALSProbe.java b/services/core/java/com/android/server/biometrics/log/ALSProbe.java
new file mode 100644
index 000000000000..62f94ed05e0a
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/log/ALSProbe.java
@@ -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();
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricLogger.java b/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
index 262be08b60e2..02b350e97ef8 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
@@ -17,21 +17,15 @@
package com.android.server.biometrics.log;
import android.annotation.NonNull;
-import android.annotation.Nullable;
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.BiometricsProtoEnums;
import android.hardware.biometrics.common.OperationContext;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
-import android.util.Log;
import android.util.Slog;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.biometrics.Utils;
@@ -43,61 +37,16 @@ public class BiometricLogger {
public static final String TAG = "BiometricLogger";
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 mStatsAction;
private final int mStatsClient;
private final BiometricFrameworkStatsLogger mSink;
- @NonNull private final SensorManager mSensorManager;
+ @NonNull private final ALSProbe mALSProbe;
private long mFirstAcquireTimeMs;
- private boolean mLightSensorEnabled = false;
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). */
public static BiometricLogger ofUnknown(@NonNull Context context) {
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 statsModality One of {@link BiometricsProtoEnums} MODALITY_* constants.
* @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants.
@@ -125,7 +79,7 @@ public class BiometricLogger {
mStatsAction = statsAction;
mStatsClient = statsClient;
mSink = logSink;
- mSensorManager = sensorManager;
+ mALSProbe = new ALSProbe(sensorManager);
}
/** 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. */
public void disableMetrics() {
mShouldLogMetrics = false;
+ mALSProbe.destroy();
}
/** {@link BiometricsProtoEnums} CLIENT_* constants */
@@ -265,7 +220,7 @@ public class BiometricLogger {
+ ", RequireConfirmation: " + requireConfirmation
+ ", State: " + authState
+ ", Latency: " + latency
- + ", Lux: " + mLastAmbientLux);
+ + ", Lux: " + mALSProbe.getCurrentLux());
} else {
Slog.v(TAG, "Authentication latency: " + latency);
}
@@ -276,7 +231,7 @@ public class BiometricLogger {
mSink.authenticate(operationContext, mStatsModality, mStatsAction, mStatsClient,
Utils.isDebugEnabled(context, targetUserId),
- latency, authState, requireConfirmation, targetUserId, mLastAmbientLux);
+ latency, authState, requireConfirmation, targetUserId, mALSProbe.getCurrentLux());
}
/** Log enrollment outcome. */
@@ -290,7 +245,7 @@ public class BiometricLogger {
+ ", User: " + targetUserId
+ ", Client: " + mStatsClient
+ ", Latency: " + latency
- + ", Lux: " + mLastAmbientLux
+ + ", Lux: " + mALSProbe.getCurrentLux()
+ ", Success: " + enrollSuccessful);
} else {
Slog.v(TAG, "Enroll latency: " + latency);
@@ -301,7 +256,7 @@ public class BiometricLogger {
}
mSink.enroll(mStatsModality, mStatsAction, mStatsClient,
- targetUserId, latency, enrollSuccessful, mLastAmbientLux);
+ targetUserId, latency, enrollSuccessful, mALSProbe.getCurrentLux());
}
/** 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
* start/stop the problem when needed.
@@ -331,53 +288,7 @@ public class BiometricLogger {
* @param startWithClient if probe should start automatically when the operation starts.
*/
@NonNull
- public CallbackWithProbe<Probe> createALSCallback(boolean startWithClient) {
- return new CallbackWithProbe<>(new ALSProbe(), 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()));
- }
- }
+ public CallbackWithProbe<Probe> getAmbientLightProbe(boolean startWithClient) {
+ return new CallbackWithProbe<>(mALSProbe, startWithClient);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index d0c58fd0545f..ca4b7475f7dc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -131,7 +131,7 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
@Override
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
return new ClientMonitorCompositeCallback(
- getLogger().createALSCallback(true /* startWithClient */), callback);
+ getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index da7853654ebf..5d62cde01a6f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -115,7 +115,7 @@ public class FaceEnrollClient extends EnrollClient<AidlSession> {
@Override
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
return new ClientMonitorCompositeCallback(mPreviewHandleDeleterCallback,
- getLogger().createALSCallback(true /* startWithClient */), callback);
+ getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 1935a5b135d7..9baca98e4d2b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -101,7 +101,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
@Override
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
return new ClientMonitorCompositeCallback(
- getLogger().createALSCallback(true /* startWithClient */), callback);
+ getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
index 226e458ad07b..16d2f7a03c6d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
@@ -75,7 +75,7 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
@Override
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
return new ClientMonitorCompositeCallback(
- getLogger().createALSCallback(true /* startWithClient */), callback);
+ getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index b530c8db3c67..1688f966eccd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -137,7 +137,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
mLockoutCache = lockoutCache;
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
mSensorProps = sensorProps;
- mALSProbeCallback = getLogger().createALSCallback(false /* startWithClient */);
+ mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
mHandler = handler;
mWaitForAuthKeyguard =
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index f4f0a19d0db7..7d2cf9deb76f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -94,7 +94,7 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
mMaxTemplatesPerUser = maxTemplatesPerUser;
- mALSProbeCallback = getLogger().createALSCallback(false /* startWithClient */);
+ mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
mEnrollReason = enrollReason;
if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 97fbb5f6e4fe..7ed1a514f9bc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -86,7 +86,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
mLockoutFrameworkImpl = lockoutTracker;
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
mSensorProps = sensorProps;
- mALSProbeCallback = getLogger().createALSCallback(false /* startWithClient */);
+ mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 2a59c8c0f204..5d9af5322c2e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -84,7 +84,7 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
@Override
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
return new ClientMonitorCompositeCallback(
- getLogger().createALSCallback(true /* startWithClient */), callback);
+ getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/ALSProbeTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/ALSProbeTest.java
new file mode 100644
index 000000000000..10f0a5cbbc40
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/ALSProbeTest.java
@@ -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();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
index 0b8e8adc5cc4..60dc2eb6081d 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
@@ -232,7 +232,7 @@ public class BiometricLoggerTest {
public void testALSCallback() {
mLogger = createLogger();
final CallbackWithProbe<Probe> callback =
- mLogger.createALSCallback(true /* startWithClient */);
+ mLogger.getAmbientLightProbe(true /* startWithClient */);
callback.onClientStarted(mClient);
verify(mSensorManager).registerListener(any(), any(), anyInt());
@@ -242,10 +242,37 @@ public class BiometricLoggerTest {
}
@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
public void testALSCallbackDoesNotStart() {
mLogger = createLogger();
final CallbackWithProbe<Probe> callback =
- mLogger.createALSCallback(false /* startWithClient */);
+ mLogger.getAmbientLightProbe(false /* startWithClient */);
callback.onClientStarted(mClient);
callback.onClientFinished(mClient, true /* success */);
@@ -256,7 +283,7 @@ public class BiometricLoggerTest {
public void testALSCallbackDestroyed() {
mLogger = createLogger();
final CallbackWithProbe<Probe> callback =
- mLogger.createALSCallback(true /* startWithClient */);
+ mLogger.getAmbientLightProbe(true /* startWithClient */);
callback.onClientStarted(mClient);
callback.onClientFinished(mClient, false /* success */);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index a149f3ee3f53..1ed52fc6a40a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -137,7 +137,7 @@ public class FingerprintAuthenticationClientTest {
@Before
public void setup() {
mContext.addMockSystemService(BiometricManager.class, mBiometricManager);
- when(mBiometricLogger.createALSCallback(anyBoolean())).thenAnswer(i ->
+ when(mBiometricLogger.getAmbientLightProbe(anyBoolean())).thenAnswer(i ->
new CallbackWithProbe<>(mLuxProbe, i.getArgument(0)));
when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
i -> i.getArgument(0));
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index f77eb0bcc59f..97fe9ea41e3d 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -119,7 +119,7 @@ public class FingerprintEnrollClientTest {
@Before
public void setup() {
- when(mBiometricLogger.createALSCallback(anyBoolean())).thenAnswer(i ->
+ when(mBiometricLogger.getAmbientLightProbe(anyBoolean())).thenAnswer(i ->
new CallbackWithProbe<>(mLuxProbe, i.getArgument(0)));
when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
i -> i.getArgument(0));