summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/biometrics/AuthenticationStatsBroadcastReceiver.java70
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricLogger.java11
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java16
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java14
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java14
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsBroadcastReceiverTest.java113
7 files changed, 231 insertions, 21 deletions
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsBroadcastReceiver.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsBroadcastReceiver.java
new file mode 100644
index 000000000000..832d73fd5d2d
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsBroadcastReceiver.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics;
+
+import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.BiometricNotificationImpl;
+
+import java.util.function.Consumer;
+
+/**
+ * Receives broadcast to initialize AuthenticationStatsCollector.
+ */
+public class AuthenticationStatsBroadcastReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "AuthenticationStatsBroadcastReceiver";
+
+ @NonNull
+ private final Consumer<AuthenticationStatsCollector> mCollectorConsumer;
+ @BiometricAuthenticator.Modality
+ private final int mModality;
+
+ public AuthenticationStatsBroadcastReceiver(@NonNull Context context,
+ @BiometricAuthenticator.Modality int modality,
+ @NonNull Consumer<AuthenticationStatsCollector> callback) {
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
+ context.registerReceiver(this, intentFilter);
+
+ mCollectorConsumer = callback;
+ mModality = modality;
+ }
+
+ @Override
+ public void onReceive(@NonNull Context context, @NonNull Intent intent) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+
+ if (userId != UserHandle.USER_NULL
+ && Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+ Slog.d(TAG, "Received: " + intent.getAction());
+
+ mCollectorConsumer.accept(
+ new AuthenticationStatsCollector(context, mModality,
+ new BiometricNotificationImpl()));
+
+ context.unregisterReceiver(this);
+ }
+ }
+}
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 87037af11a84..dbef7178efd0 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
@@ -17,6 +17,7 @@
package com.android.server.biometrics.log;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.hardware.SensorManager;
import android.hardware.biometrics.BiometricConstants;
@@ -42,7 +43,7 @@ public class BiometricLogger {
private final int mStatsAction;
private final int mStatsClient;
private final BiometricFrameworkStatsLogger mSink;
- @NonNull private final AuthenticationStatsCollector mAuthenticationStatsCollector;
+ @Nullable private final AuthenticationStatsCollector mAuthenticationStatsCollector;
@NonNull private final ALSProbe mALSProbe;
private long mFirstAcquireTimeMs;
@@ -68,7 +69,7 @@ public class BiometricLogger {
*/
public BiometricLogger(
@NonNull Context context, int statsModality, int statsAction, int statsClient,
- AuthenticationStatsCollector authenticationStatsCollector) {
+ @Nullable AuthenticationStatsCollector authenticationStatsCollector) {
this(statsModality, statsAction, statsClient,
BiometricFrameworkStatsLogger.getInstance(),
authenticationStatsCollector,
@@ -79,7 +80,7 @@ public class BiometricLogger {
BiometricLogger(
int statsModality, int statsAction, int statsClient,
BiometricFrameworkStatsLogger logSink,
- @NonNull AuthenticationStatsCollector statsCollector,
+ @Nullable AuthenticationStatsCollector statsCollector,
SensorManager sensorManager) {
mStatsModality = statsModality;
mStatsAction = statsAction;
@@ -206,7 +207,9 @@ public class BiometricLogger {
return;
}
- mAuthenticationStatsCollector.authenticate(targetUserId, authenticated);
+ if (mAuthenticationStatsCollector != null) {
+ mAuthenticationStatsCollector.authenticate(targetUserId, authenticated);
+ }
int authState = FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__UNKNOWN;
if (!authenticated) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 28f0a4dadbd5..cc3118cc3433 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -49,6 +49,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.biometrics.AuthenticationStatsBroadcastReceiver;
import com.android.server.biometrics.AuthenticationStatsCollector;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
@@ -56,7 +57,6 @@ import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
-import com.android.server.biometrics.sensors.BiometricNotificationImpl;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -114,8 +114,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
private final BiometricContext mBiometricContext;
@NonNull
private final AuthSessionCoordinator mAuthSessionCoordinator;
- @NonNull
- private final AuthenticationStatsCollector mAuthenticationStatsCollector;
+ @Nullable
+ private AuthenticationStatsCollector mAuthenticationStatsCollector;
@Nullable
private IFace mDaemon;
@@ -177,8 +177,14 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator();
mDaemon = daemon;
- mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
- BiometricsProtoEnums.MODALITY_FACE, new BiometricNotificationImpl());
+ AuthenticationStatsBroadcastReceiver mBroadcastReceiver =
+ new AuthenticationStatsBroadcastReceiver(
+ mContext,
+ BiometricsProtoEnums.MODALITY_FACE,
+ (AuthenticationStatsCollector collector) -> {
+ Slog.d(getTag(), "Initializing AuthenticationStatsCollector");
+ mAuthenticationStatsCollector = collector;
+ });
for (SensorProps prop : props) {
final int sensorId = prop.commonProps.sensorId;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index 808626120c1e..1499317478aa 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -52,6 +52,7 @@ import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.biometrics.AuthenticationStatsBroadcastReceiver;
import com.android.server.biometrics.AuthenticationStatsCollector;
import com.android.server.biometrics.SensorServiceStateProto;
import com.android.server.biometrics.SensorStateProto;
@@ -62,7 +63,6 @@ import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AcquisitionClient;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
-import com.android.server.biometrics.sensors.BiometricNotificationImpl;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -125,7 +125,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
@Nullable private IBiometricsFace mDaemon;
@NonNull private final HalResultController mHalResultController;
@NonNull private final BiometricContext mBiometricContext;
- @NonNull private final AuthenticationStatsCollector mAuthenticationStatsCollector;
+ @Nullable private AuthenticationStatsCollector mAuthenticationStatsCollector;
// for requests that do not use biometric prompt
@NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
private int mCurrentUserId = UserHandle.USER_NULL;
@@ -366,8 +366,14 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
mCurrentUserId = UserHandle.USER_NULL;
});
- mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
- BiometricsProtoEnums.MODALITY_FACE, new BiometricNotificationImpl());
+ AuthenticationStatsBroadcastReceiver mBroadcastReceiver =
+ new AuthenticationStatsBroadcastReceiver(
+ mContext,
+ BiometricsProtoEnums.MODALITY_FACE,
+ (AuthenticationStatsCollector collector) -> {
+ Slog.d(TAG, "Initializing AuthenticationStatsCollector");
+ mAuthenticationStatsCollector = collector;
+ });
try {
ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 5f4b89439fd0..f74b45cbdb0e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -57,6 +57,7 @@ import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.biometrics.AuthenticationStatsBroadcastReceiver;
import com.android.server.biometrics.AuthenticationStatsCollector;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
@@ -64,7 +65,6 @@ import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
-import com.android.server.biometrics.sensors.BiometricNotificationImpl;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -124,7 +124,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
@Nullable private ISidefpsController mSidefpsController;
private AuthSessionCoordinator mAuthSessionCoordinator;
- @NonNull private final AuthenticationStatsCollector mAuthenticationStatsCollector;
+ @Nullable private AuthenticationStatsCollector mAuthenticationStatsCollector;
private final class BiometricTaskStackListener extends TaskStackListener {
@Override
@@ -184,8 +184,14 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator();
mDaemon = daemon;
- mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
- BiometricsProtoEnums.MODALITY_FINGERPRINT, new BiometricNotificationImpl());
+ AuthenticationStatsBroadcastReceiver mBroadcastReceiver =
+ new AuthenticationStatsBroadcastReceiver(
+ mContext,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT,
+ (AuthenticationStatsCollector collector) -> {
+ Slog.d(getTag(), "Initializing AuthenticationStatsCollector");
+ mAuthenticationStatsCollector = collector;
+ });
final List<SensorLocationInternal> workaroundLocations = getWorkaroundSensorProps(context);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index d0b71fcf2dbb..a655f3601a07 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -52,6 +52,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.biometrics.AuthenticationStatsBroadcastReceiver;
import com.android.server.biometrics.AuthenticationStatsCollector;
import com.android.server.biometrics.SensorServiceStateProto;
import com.android.server.biometrics.SensorStateProto;
@@ -66,7 +67,6 @@ import com.android.server.biometrics.sensors.AcquisitionClient;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
-import com.android.server.biometrics.sensors.BiometricNotificationImpl;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -125,7 +125,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
@Nullable private ISidefpsController mSidefpsController;
@NonNull private final BiometricContext mBiometricContext;
- @NonNull private final AuthenticationStatsCollector mAuthenticationStatsCollector;
+ @Nullable private AuthenticationStatsCollector mAuthenticationStatsCollector;
// for requests that do not use biometric prompt
@NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
private int mCurrentUserId = UserHandle.USER_NULL;
@@ -354,8 +354,14 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mCurrentUserId = UserHandle.USER_NULL;
});
- mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
- BiometricsProtoEnums.MODALITY_FINGERPRINT, new BiometricNotificationImpl());
+ AuthenticationStatsBroadcastReceiver mBroadcastReceiver =
+ new AuthenticationStatsBroadcastReceiver(
+ mContext,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT,
+ (AuthenticationStatsCollector collector) -> {
+ Slog.d(TAG, "Initializing AuthenticationStatsCollector");
+ mAuthenticationStatsCollector = collector;
+ });
try {
ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsBroadcastReceiverTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsBroadcastReceiverTest.java
new file mode 100644
index 000000000000..f4e5faaf2103
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsBroadcastReceiverTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anySet;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static java.util.Collections.emptySet;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.os.UserHandle;
+
+import com.android.internal.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.io.File;
+import java.util.function.Consumer;
+
+public class AuthenticationStatsBroadcastReceiverTest {
+
+ @Rule
+ public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ private AuthenticationStatsBroadcastReceiver mBroadcastReceiver;
+ private static final float FRR_THRESHOLD = 0.2f;
+ private static final int USER_ID_1 = 1;
+
+ @Mock
+ Context mContext;
+ @Mock
+ private Resources mResources;
+ @Mock
+ private SharedPreferences mSharedPreferences;
+ @Mock
+ private SharedPreferences.Editor mEditor;
+ @Mock
+ Intent mIntent;
+ @Mock
+ Consumer<AuthenticationStatsCollector> mCallback;
+
+ @Captor
+ private ArgumentCaptor<AuthenticationStatsCollector> mArgumentCaptor;
+
+ @Before
+ public void setUp() {
+
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getFraction(eq(R.fraction.config_biometricNotificationFrrThreshold),
+ anyInt(), anyInt())).thenReturn(FRR_THRESHOLD);
+ when(mContext.getSharedPreferences(any(File.class), anyInt()))
+ .thenReturn(mSharedPreferences);
+ when(mSharedPreferences.getStringSet(anyString(), anySet())).thenReturn(emptySet());
+ when(mSharedPreferences.edit()).thenReturn(mEditor);
+ when(mEditor.putFloat(anyString(), anyFloat())).thenReturn(mEditor);
+ when(mEditor.putStringSet(anyString(), anySet())).thenReturn(mEditor);
+
+ when(mIntent.getAction()).thenReturn(Intent.ACTION_USER_UNLOCKED);
+ when(mIntent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL))
+ .thenReturn(USER_ID_1);
+
+ mBroadcastReceiver = new AuthenticationStatsBroadcastReceiver(mContext,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT, mCallback);
+ }
+
+ @Test
+ public void testRegisterReceiver() {
+ verify(mContext).registerReceiver(eq(mBroadcastReceiver), any());
+ }
+
+ @Test
+ public void testOnReceive_shouldInitializeAuthenticationStatsCollector() {
+ mBroadcastReceiver.onReceive(mContext, mIntent);
+
+ // Verify AuthenticationStatsCollector is initialized
+ verify(mCallback).accept(mArgumentCaptor.capture());
+ assertThat(mArgumentCaptor.getValue()).isNotNull();
+
+ // Verify receiver is unregistered after receiving the broadcast
+ verify(mContext).unregisterReceiver(mBroadcastReceiver);
+ }
+}