diff options
| author | 2022-08-29 19:57:25 +0000 | |
|---|---|---|
| committer | 2022-08-29 19:57:25 +0000 | |
| commit | bb1fe494eedad6c6785ccd960377f80dc0948f9c (patch) | |
| tree | 393b26556b9b4f3cbe7c7327968d01fae7f6b91f | |
| parent | c861151f1af7ed6ffa3ca653d216d70e040822fb (diff) | |
| parent | 15be0582446e6333a6ddefa6c64ec0fd4ca6060e (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>
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)); |