Loading services/core/java/com/android/server/biometrics/biometrics.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -51,3 +51,14 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "internal_cleanup_for_all_profiles" namespace: "biometrics_framework" description: "Feature flag for scheduling internal cleanup for all profiles" bug: "441557507" metadata { purpose: PURPOSE_BUGFIX } } services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +22 −25 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.biometrics.sensors.face.aidl; import static android.hardware.face.FaceSensorConfigurations.getIFace; import static android.hardware.face.FaceSensorConfigurations.remapFqName; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -90,6 +89,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; /** * Provider for a single instance of the {@link IFace} HAL. Loading Loading @@ -118,10 +118,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { private final LockoutResetDispatcher mLockoutResetDispatcher; @NonNull private final UsageStats mUsageStats; @NonNull private final ActivityTaskManager mActivityTaskManager; @NonNull private final BiometricTaskStackListener mTaskStackListener; // for requests that do not use biometric prompt @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); Loading @@ -131,6 +127,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { private final AuthSessionCoordinator mAuthSessionCoordinator; @NonNull private final BiometricHandlerProvider mBiometricHandlerProvider; @NonNull private final Function<String, IFace> mGetIFace; @Nullable private AuthenticationStatsCollector mAuthenticationStatsCollector; @Nullable Loading Loading @@ -179,7 +177,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { boolean resetLockoutRequiresChallenge) { this(context, biometricStateCallback, authenticationStateListeners, props, halInstanceName, lockoutResetDispatcher, biometricContext, null /* daemon */, BiometricHandlerProvider.getInstance(), resetLockoutRequiresChallenge, BiometricHandlerProvider.getInstance(), (fqname) -> getIFace(fqname), resetLockoutRequiresChallenge, false /* testHalEnabled */); } Loading @@ -192,6 +191,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { @NonNull BiometricContext biometricContext, @Nullable IFace daemon, @NonNull BiometricHandlerProvider biometricHandlerProvider, @NonNull Function<String, IFace> getIFace, boolean resetLockoutRequiresChallenge, boolean testHalEnabled) { mContext = context; Loading @@ -202,11 +202,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { mHandler = biometricHandlerProvider.getFaceHandler(); mUsageStats = new UsageStats(context); mLockoutResetDispatcher = lockoutResetDispatcher; mActivityTaskManager = ActivityTaskManager.getInstance(); mTaskStackListener = new BiometricTaskStackListener(); mBiometricContext = biometricContext; mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator(); mDaemon = daemon; mGetIFace = getIFace; mTestHalEnabled = testHalEnabled; mBiometricHandlerProvider = biometricHandlerProvider; Loading Loading @@ -292,14 +291,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { return TAG + "/" + mHalInstanceName; } boolean hasHalInstance() { if (mTestHalEnabled) { return true; } return ServiceManager.checkService( remapFqName(IFace.DESCRIPTOR + "/" + mHalInstanceName)) != null; } @Nullable @VisibleForTesting synchronized IFace getHalInstance() { Loading Loading @@ -335,7 +326,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { Slog.d(getTag(), "Daemon was null, reconnecting"); mDaemon = getIFace(IFace.DESCRIPTOR + "/" + mHalInstanceNameCurrent); mDaemon = mGetIFace.apply(IFace.DESCRIPTOR + "/" + mHalInstanceNameCurrent); if (mDaemon == null) { Slog.e(getTag(), "Unable to get daemon"); return null; Loading @@ -349,7 +340,11 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { for (int i = 0; i < mFaceSensors.size(); i++) { final int sensorId = mFaceSensors.keyAt(i); if (Flags.internalCleanupForAllProfiles()) { processFaceForProfiles(sensorId); } else { scheduleLoadAuthenticatorIds(sensorId); } scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(), null /* callback */); } Loading Loading @@ -391,6 +386,15 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { } } private void processFaceForProfiles(int sensorId) { for (UserInfo user : UserManager.get(mContext).getAliveUsers()) { if (user.id != ActivityManager.getCurrentUser()) { scheduleInternalCleanup(sensorId, user.id, null /* callback */); } scheduleLoadAuthenticatorIdsForUser(sensorId, user.id); } } /** * Schedules FaceGetAuthenticatorIdClient for specific sensor and user. */ Loading Loading @@ -897,13 +901,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { mAuthenticationStatsCollector.sendFaceReEnrollNotification(); } /** * Sends a fingerprint enroll notification. */ public void sendFingerprintReEnrollNotification() { mAuthenticationStatsCollector.sendFingerprintReEnrollNotification(); } /** * Return virtual hal AIDL interface if it is used for testing * Loading services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +21 −16 Original line number Diff line number Diff line Loading @@ -17,8 +17,6 @@ package com.android.server.biometrics.sensors.fingerprint.aidl; import static android.hardware.fingerprint.FingerprintManager.SENSOR_ID_ANY; import static android.hardware.fingerprint.FingerprintSensorConfigurations.getIFingerprint; import static android.hardware.fingerprint.FingerprintSensorConfigurations.remapFqName; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -43,6 +41,7 @@ import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintAuthenticateOptions; import android.hardware.fingerprint.FingerprintEnrollOptions; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorConfigurations; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.IUdfpsOverlayController; Loading Loading @@ -96,6 +95,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; /** * Provider for a single instance of the {@link IFingerprint} HAL. Loading Loading @@ -123,13 +123,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; @NonNull private final ActivityTaskManager mActivityTaskManager; @NonNull private final BiometricTaskStackListener mTaskStackListener; // for requests that do not use biometric prompt @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); @NonNull private final BiometricContext mBiometricContext; @NonNull private final BiometricHandlerProvider mBiometricHandlerProvider; @NonNull private final Function<String, IFingerprint> mGetIFingerprint; @Nullable private IFingerprint mDaemon; @Nullable private IUdfpsOverlayController mUdfpsOverlayController; private final AuthSessionCoordinator mAuthSessionCoordinator; Loading Loading @@ -177,6 +176,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi this(context, biometricStateCallback, authenticationStateListeners, props, halInstanceName, lockoutResetDispatcher, gestureAvailabilityDispatcher, biometricContext, null /* daemon */, BiometricHandlerProvider.getInstance(), FingerprintSensorConfigurations::getIFingerprint, resetLockoutRequiresHardwareAuthToken, false /* testHalEnabled */); } Loading @@ -189,6 +189,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @NonNull BiometricContext biometricContext, @Nullable IFingerprint daemon, @NonNull BiometricHandlerProvider biometricHandlerProvider, @NonNull Function<String, IFingerprint> getIFingerprint, boolean resetLockoutRequiresHardwareAuthToken, boolean testHalEnabled) { mContext = context; Loading @@ -198,11 +199,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi mFingerprintSensors = new SensorList<>(ActivityManager.getService()); mHandler = biometricHandlerProvider.getFingerprintHandler(); mLockoutResetDispatcher = lockoutResetDispatcher; mActivityTaskManager = ActivityTaskManager.getInstance(); mTaskStackListener = new BiometricTaskStackListener(); mBiometricContext = biometricContext; mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator(); mDaemon = daemon; mGetIFingerprint = getIFingerprint; mTestHalEnabled = testHalEnabled; mBiometricHandlerProvider = biometricHandlerProvider; Loading Loading @@ -289,15 +290,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi return TAG + "/" + mHalInstanceName; } boolean hasHalInstance() { if (mTestHalEnabled) { return true; } return (ServiceManager.checkService( remapFqName(IFingerprint.DESCRIPTOR + "/" + mHalInstanceName)) != null); } @Nullable @VisibleForTesting synchronized IFingerprint getHalInstance() { Loading Loading @@ -333,7 +325,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi Slog.d(getTag(), "Daemon was null, reconnecting"); mDaemon = getIFingerprint(IFingerprint.DESCRIPTOR + "/" + mHalInstanceNameCurrent); mDaemon = mGetIFingerprint.apply(IFingerprint.DESCRIPTOR + "/" + mHalInstanceNameCurrent); if (mDaemon == null) { Slog.e(getTag(), "Unable to get daemon"); return null; Loading @@ -347,7 +339,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi for (int i = 0; i < mFingerprintSensors.size(); i++) { final int sensorId = mFingerprintSensors.keyAt(i); if (Flags.internalCleanupForAllProfiles()) { processFingerprintForProfiles(sensorId); } else { scheduleLoadAuthenticatorIds(sensorId); } scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(), null /* callback */); } Loading Loading @@ -418,6 +414,15 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } } private void processFingerprintForProfiles(int sensorId) { for (UserInfo user : UserManager.get(mContext).getAliveUsers()) { if (user.id != ActivityManager.getCurrentUser()) { scheduleInternalCleanup(sensorId, user.id, null /* callback */); } scheduleLoadAuthenticatorIdsForUser(sensorId, user.id); } } /** * Schedules FingerprintGetAuthenticatorIdClient for specific sensor and user. */ Loading services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java +39 −5 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.UserInfo; import android.content.res.Resources; import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.common.CommonProps; Loading @@ -49,6 +50,7 @@ import android.os.RemoteException; import android.os.UserManager; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; Loading @@ -56,6 +58,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.server.biometrics.BiometricHandlerProvider; import com.android.server.biometrics.Flags; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.sensors.AuthSessionCoordinator; import com.android.server.biometrics.sensors.AuthenticationStateListeners; Loading @@ -74,7 +77,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; @Presubmit @SmallTest Loading @@ -85,6 +88,7 @@ public class FaceProviderTest { DeviceFlagsValueProvider.createCheckFlagsRule(); private static final String TAG = "FaceProviderTest"; private static final List<Integer> ALIVE_USERS = List.of(0, 1, 2); private static final float FRR_THRESHOLD = 0.2f; Loading @@ -110,6 +114,8 @@ public class FaceProviderTest { private BiometricScheduler<IFace, ISession> mScheduler; @Mock AuthSessionCoordinator mAuthSessionCoordinator; @Mock private IBinder mBinder; private final TestLooper mLooper = new TestLooper(); private SensorProps[] mSensorProps; Loading @@ -121,9 +127,10 @@ public class FaceProviderTest { MockitoAnnotations.initMocks(this); when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>()); when(mUserManager.getAliveUsers()).thenReturn( ALIVE_USERS.stream().map(i -> new UserInfo(i, "", 0)).toList()); when(mDaemon.createSession(anyInt(), anyInt(), any())).thenReturn(mock(ISession.class)); when(mDaemon.asBinder()).thenReturn(mBinder); when(mContext.getResources()).thenReturn(mResources); when(mResources.getFraction(R.fraction.config_biometricNotificationFrrThreshold, 1, 1)) .thenReturn(FRR_THRESHOLD); Loading @@ -146,8 +153,10 @@ public class FaceProviderTest { mFaceProvider = new FaceProvider(mContext, mBiometricStateCallback, mAuthenticationStateListeners, mSensorProps, TAG, mLockoutResetDispatcher, mBiometricContext, mDaemon, mBiometricHandlerProvider, mBiometricContext, mDaemon, mBiometricHandlerProvider, (fqName) -> mDaemon, false /* resetLockoutRequiresChallenge */, false /* testHalEnabled */); waitForIdle(); } @Test Loading Loading @@ -181,7 +190,8 @@ public class FaceProviderTest { mFaceProvider = new FaceProvider(mContext, mBiometricStateCallback, mAuthenticationStateListeners, hidlFaceSensorConfig, TAG, mLockoutResetDispatcher, mBiometricContext, mDaemon, mBiometricHandlerProvider, true /* resetLockoutRequiresChallenge */, mBiometricHandlerProvider, (fqName) -> mDaemon, true /* resetLockoutRequiresChallenge */, true /* testHalEnabled */); assertThat(mFaceProvider.mFaceSensors.get(faceId) Loading Loading @@ -283,6 +293,30 @@ public class FaceProviderTest { anyBoolean()); } @Test @RequiresFlagsEnabled(Flags.FLAG_INTERNAL_CLEANUP_FOR_ALL_PROFILES) public void testGetHalInstance_whenDaemonIsNull() { mFaceProvider.setTestHalEnabled(false); for (SensorProps sensor: mSensorProps) { mFaceProvider.mFaceSensors.get(sensor.commonProps.sensorId).setScheduler(mScheduler); } //Reset value of FaceProvider#mDaemon mFaceProvider.binderDied(); waitForIdle(); final IFace daemon = mFaceProvider.getHalInstance(); waitForIdle(); assertNotNull(daemon); verify(mScheduler, times(ALIVE_USERS.size() * mSensorProps.length)) .scheduleClientMonitor(any(FaceInternalCleanupClient.class), any(ClientMonitorCallback.class)); verify(mScheduler, times(ALIVE_USERS.size() * mSensorProps.length)) .scheduleClientMonitor(any(FaceGetAuthenticatorIdClient.class)); } private void waitForIdle() { mLooper.dispatchAll(); } Loading services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java +44 −4 Original line number Diff line number Diff line Loading @@ -34,7 +34,9 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.content.Context; import android.content.pm.UserInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.hardware.biometrics.IBiometricSensorReceiver; Loading @@ -52,12 +54,14 @@ import android.os.RemoteException; import android.os.UserManager; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.filters.SmallTest; import com.android.server.biometrics.BiometricHandlerProvider; import com.android.server.biometrics.Flags; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.sensors.AuthSessionCoordinator; import com.android.server.biometrics.sensors.AuthenticationStateListeners; Loading @@ -78,13 +82,16 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; @Presubmit @SmallTest public class FingerprintProviderTest { private static final String TAG = "FingerprintProviderTest"; private static final int CURRENT_USER_ID = ActivityManager.getCurrentUser(); private static final List<Integer> ALIVE_USERS = List.of(CURRENT_USER_ID, CURRENT_USER_ID + 1, CURRENT_USER_ID + 2); @Rule public final CheckFlagsRule mCheckFlagsRule = Loading Loading @@ -116,6 +123,8 @@ public class FingerprintProviderTest { private AuthSessionCoordinator mAuthSessionCoordinator; @Mock private BiometricScheduler<IFingerprint, ISession> mScheduler; @Mock private IBinder mBinder; private final TestLooper mLooper = new TestLooper(); Loading @@ -130,8 +139,10 @@ public class FingerprintProviderTest { when(mContext.getResources()).thenReturn(mResources); when(mResources.obtainTypedArray(anyInt())).thenReturn(mock(TypedArray.class)); when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>()); when(mUserManager.getAliveUsers()).thenReturn( ALIVE_USERS.stream().map(i -> new UserInfo(i, "", 0)).toList()); when(mDaemon.createSession(anyInt(), anyInt(), any())).thenReturn(mock(ISession.class)); when(mDaemon.asBinder()).thenReturn(mBinder); when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator); when(mBiometricHandlerProvider.getBiometricCallbackHandler()).thenReturn( mBiometricCallbackHandler); Loading @@ -154,8 +165,10 @@ public class FingerprintProviderTest { mFingerprintProvider = new FingerprintProvider(mContext, mBiometricStateCallback, mAuthenticationStateListeners, mSensorProps, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext, mDaemon, mBiometricHandlerProvider, mDaemon, mBiometricHandlerProvider, (fqName) -> mDaemon, false /* resetLockoutRequiresHardwareAuthToken */, true /* testHalEnabled */); waitForIdle(); } @Test Loading Loading @@ -187,6 +200,7 @@ public class FingerprintProviderTest { hidlFingerprintSensorConfigs, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext, mDaemon, mBiometricHandlerProvider, (fqName) -> mDaemon, false /* resetLockoutRequiresHardwareAuthToken */, true /* testHalEnabled */); Loading Loading @@ -301,7 +315,7 @@ public class FingerprintProviderTest { mFingerprintProvider = new FingerprintProvider(mContext, mBiometricStateCallback, mAuthenticationStateListeners, mSensorProps, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext, mDaemon, mBiometricHandlerProvider, mDaemon, mBiometricHandlerProvider, (fqName) -> mDaemon, false /* resetLockoutRequiresHardwareAuthToken */, true /* testHalEnabled */); waitForIdle(); Loading @@ -313,6 +327,32 @@ public class FingerprintProviderTest { verify(mFingerprintHandler).sendMessageDelayed(any(), anyLong()); } @Test @RequiresFlagsEnabled(Flags.FLAG_INTERNAL_CLEANUP_FOR_ALL_PROFILES) public void testGetHalInstance_whenDaemonIsNull() { mFingerprintProvider.setTestHalEnabled(false); for (SensorProps sensor : mSensorProps) { mFingerprintProvider.mFingerprintSensors.get(sensor.commonProps.sensorId).setScheduler( mScheduler); } //Reset value of FingerprintProvider#mDaemon mFingerprintProvider.binderDied(); waitForIdle(); final IFingerprint daemon = mFingerprintProvider.getHalInstance(); waitForIdle(); assertNotNull(daemon); verify(mScheduler, times(ALIVE_USERS.size() * mSensorProps.length)) .scheduleClientMonitor(any(FingerprintInternalCleanupClient.class), any(ClientMonitorCallback.class)); verify(mScheduler, times(ALIVE_USERS.size() * mSensorProps.length)) .scheduleClientMonitor(any(FingerprintGetAuthenticatorIdClient.class)); } private void waitForIdle() { mLooper.dispatchAll(); } Loading Loading
services/core/java/com/android/server/biometrics/biometrics.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -51,3 +51,14 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "internal_cleanup_for_all_profiles" namespace: "biometrics_framework" description: "Feature flag for scheduling internal cleanup for all profiles" bug: "441557507" metadata { purpose: PURPOSE_BUGFIX } }
services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +22 −25 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.biometrics.sensors.face.aidl; import static android.hardware.face.FaceSensorConfigurations.getIFace; import static android.hardware.face.FaceSensorConfigurations.remapFqName; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -90,6 +89,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; /** * Provider for a single instance of the {@link IFace} HAL. Loading Loading @@ -118,10 +118,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { private final LockoutResetDispatcher mLockoutResetDispatcher; @NonNull private final UsageStats mUsageStats; @NonNull private final ActivityTaskManager mActivityTaskManager; @NonNull private final BiometricTaskStackListener mTaskStackListener; // for requests that do not use biometric prompt @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); Loading @@ -131,6 +127,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { private final AuthSessionCoordinator mAuthSessionCoordinator; @NonNull private final BiometricHandlerProvider mBiometricHandlerProvider; @NonNull private final Function<String, IFace> mGetIFace; @Nullable private AuthenticationStatsCollector mAuthenticationStatsCollector; @Nullable Loading Loading @@ -179,7 +177,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { boolean resetLockoutRequiresChallenge) { this(context, biometricStateCallback, authenticationStateListeners, props, halInstanceName, lockoutResetDispatcher, biometricContext, null /* daemon */, BiometricHandlerProvider.getInstance(), resetLockoutRequiresChallenge, BiometricHandlerProvider.getInstance(), (fqname) -> getIFace(fqname), resetLockoutRequiresChallenge, false /* testHalEnabled */); } Loading @@ -192,6 +191,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { @NonNull BiometricContext biometricContext, @Nullable IFace daemon, @NonNull BiometricHandlerProvider biometricHandlerProvider, @NonNull Function<String, IFace> getIFace, boolean resetLockoutRequiresChallenge, boolean testHalEnabled) { mContext = context; Loading @@ -202,11 +202,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { mHandler = biometricHandlerProvider.getFaceHandler(); mUsageStats = new UsageStats(context); mLockoutResetDispatcher = lockoutResetDispatcher; mActivityTaskManager = ActivityTaskManager.getInstance(); mTaskStackListener = new BiometricTaskStackListener(); mBiometricContext = biometricContext; mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator(); mDaemon = daemon; mGetIFace = getIFace; mTestHalEnabled = testHalEnabled; mBiometricHandlerProvider = biometricHandlerProvider; Loading Loading @@ -292,14 +291,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { return TAG + "/" + mHalInstanceName; } boolean hasHalInstance() { if (mTestHalEnabled) { return true; } return ServiceManager.checkService( remapFqName(IFace.DESCRIPTOR + "/" + mHalInstanceName)) != null; } @Nullable @VisibleForTesting synchronized IFace getHalInstance() { Loading Loading @@ -335,7 +326,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { Slog.d(getTag(), "Daemon was null, reconnecting"); mDaemon = getIFace(IFace.DESCRIPTOR + "/" + mHalInstanceNameCurrent); mDaemon = mGetIFace.apply(IFace.DESCRIPTOR + "/" + mHalInstanceNameCurrent); if (mDaemon == null) { Slog.e(getTag(), "Unable to get daemon"); return null; Loading @@ -349,7 +340,11 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { for (int i = 0; i < mFaceSensors.size(); i++) { final int sensorId = mFaceSensors.keyAt(i); if (Flags.internalCleanupForAllProfiles()) { processFaceForProfiles(sensorId); } else { scheduleLoadAuthenticatorIds(sensorId); } scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(), null /* callback */); } Loading Loading @@ -391,6 +386,15 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { } } private void processFaceForProfiles(int sensorId) { for (UserInfo user : UserManager.get(mContext).getAliveUsers()) { if (user.id != ActivityManager.getCurrentUser()) { scheduleInternalCleanup(sensorId, user.id, null /* callback */); } scheduleLoadAuthenticatorIdsForUser(sensorId, user.id); } } /** * Schedules FaceGetAuthenticatorIdClient for specific sensor and user. */ Loading Loading @@ -897,13 +901,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { mAuthenticationStatsCollector.sendFaceReEnrollNotification(); } /** * Sends a fingerprint enroll notification. */ public void sendFingerprintReEnrollNotification() { mAuthenticationStatsCollector.sendFingerprintReEnrollNotification(); } /** * Return virtual hal AIDL interface if it is used for testing * Loading
services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +21 −16 Original line number Diff line number Diff line Loading @@ -17,8 +17,6 @@ package com.android.server.biometrics.sensors.fingerprint.aidl; import static android.hardware.fingerprint.FingerprintManager.SENSOR_ID_ANY; import static android.hardware.fingerprint.FingerprintSensorConfigurations.getIFingerprint; import static android.hardware.fingerprint.FingerprintSensorConfigurations.remapFqName; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -43,6 +41,7 @@ import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintAuthenticateOptions; import android.hardware.fingerprint.FingerprintEnrollOptions; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorConfigurations; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.IUdfpsOverlayController; Loading Loading @@ -96,6 +95,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; /** * Provider for a single instance of the {@link IFingerprint} HAL. Loading Loading @@ -123,13 +123,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; @NonNull private final ActivityTaskManager mActivityTaskManager; @NonNull private final BiometricTaskStackListener mTaskStackListener; // for requests that do not use biometric prompt @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); @NonNull private final BiometricContext mBiometricContext; @NonNull private final BiometricHandlerProvider mBiometricHandlerProvider; @NonNull private final Function<String, IFingerprint> mGetIFingerprint; @Nullable private IFingerprint mDaemon; @Nullable private IUdfpsOverlayController mUdfpsOverlayController; private final AuthSessionCoordinator mAuthSessionCoordinator; Loading Loading @@ -177,6 +176,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi this(context, biometricStateCallback, authenticationStateListeners, props, halInstanceName, lockoutResetDispatcher, gestureAvailabilityDispatcher, biometricContext, null /* daemon */, BiometricHandlerProvider.getInstance(), FingerprintSensorConfigurations::getIFingerprint, resetLockoutRequiresHardwareAuthToken, false /* testHalEnabled */); } Loading @@ -189,6 +189,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @NonNull BiometricContext biometricContext, @Nullable IFingerprint daemon, @NonNull BiometricHandlerProvider biometricHandlerProvider, @NonNull Function<String, IFingerprint> getIFingerprint, boolean resetLockoutRequiresHardwareAuthToken, boolean testHalEnabled) { mContext = context; Loading @@ -198,11 +199,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi mFingerprintSensors = new SensorList<>(ActivityManager.getService()); mHandler = biometricHandlerProvider.getFingerprintHandler(); mLockoutResetDispatcher = lockoutResetDispatcher; mActivityTaskManager = ActivityTaskManager.getInstance(); mTaskStackListener = new BiometricTaskStackListener(); mBiometricContext = biometricContext; mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator(); mDaemon = daemon; mGetIFingerprint = getIFingerprint; mTestHalEnabled = testHalEnabled; mBiometricHandlerProvider = biometricHandlerProvider; Loading Loading @@ -289,15 +290,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi return TAG + "/" + mHalInstanceName; } boolean hasHalInstance() { if (mTestHalEnabled) { return true; } return (ServiceManager.checkService( remapFqName(IFingerprint.DESCRIPTOR + "/" + mHalInstanceName)) != null); } @Nullable @VisibleForTesting synchronized IFingerprint getHalInstance() { Loading Loading @@ -333,7 +325,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi Slog.d(getTag(), "Daemon was null, reconnecting"); mDaemon = getIFingerprint(IFingerprint.DESCRIPTOR + "/" + mHalInstanceNameCurrent); mDaemon = mGetIFingerprint.apply(IFingerprint.DESCRIPTOR + "/" + mHalInstanceNameCurrent); if (mDaemon == null) { Slog.e(getTag(), "Unable to get daemon"); return null; Loading @@ -347,7 +339,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi for (int i = 0; i < mFingerprintSensors.size(); i++) { final int sensorId = mFingerprintSensors.keyAt(i); if (Flags.internalCleanupForAllProfiles()) { processFingerprintForProfiles(sensorId); } else { scheduleLoadAuthenticatorIds(sensorId); } scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(), null /* callback */); } Loading Loading @@ -418,6 +414,15 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } } private void processFingerprintForProfiles(int sensorId) { for (UserInfo user : UserManager.get(mContext).getAliveUsers()) { if (user.id != ActivityManager.getCurrentUser()) { scheduleInternalCleanup(sensorId, user.id, null /* callback */); } scheduleLoadAuthenticatorIdsForUser(sensorId, user.id); } } /** * Schedules FingerprintGetAuthenticatorIdClient for specific sensor and user. */ Loading
services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java +39 −5 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.UserInfo; import android.content.res.Resources; import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.common.CommonProps; Loading @@ -49,6 +50,7 @@ import android.os.RemoteException; import android.os.UserManager; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; Loading @@ -56,6 +58,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.server.biometrics.BiometricHandlerProvider; import com.android.server.biometrics.Flags; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.sensors.AuthSessionCoordinator; import com.android.server.biometrics.sensors.AuthenticationStateListeners; Loading @@ -74,7 +77,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; @Presubmit @SmallTest Loading @@ -85,6 +88,7 @@ public class FaceProviderTest { DeviceFlagsValueProvider.createCheckFlagsRule(); private static final String TAG = "FaceProviderTest"; private static final List<Integer> ALIVE_USERS = List.of(0, 1, 2); private static final float FRR_THRESHOLD = 0.2f; Loading @@ -110,6 +114,8 @@ public class FaceProviderTest { private BiometricScheduler<IFace, ISession> mScheduler; @Mock AuthSessionCoordinator mAuthSessionCoordinator; @Mock private IBinder mBinder; private final TestLooper mLooper = new TestLooper(); private SensorProps[] mSensorProps; Loading @@ -121,9 +127,10 @@ public class FaceProviderTest { MockitoAnnotations.initMocks(this); when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>()); when(mUserManager.getAliveUsers()).thenReturn( ALIVE_USERS.stream().map(i -> new UserInfo(i, "", 0)).toList()); when(mDaemon.createSession(anyInt(), anyInt(), any())).thenReturn(mock(ISession.class)); when(mDaemon.asBinder()).thenReturn(mBinder); when(mContext.getResources()).thenReturn(mResources); when(mResources.getFraction(R.fraction.config_biometricNotificationFrrThreshold, 1, 1)) .thenReturn(FRR_THRESHOLD); Loading @@ -146,8 +153,10 @@ public class FaceProviderTest { mFaceProvider = new FaceProvider(mContext, mBiometricStateCallback, mAuthenticationStateListeners, mSensorProps, TAG, mLockoutResetDispatcher, mBiometricContext, mDaemon, mBiometricHandlerProvider, mBiometricContext, mDaemon, mBiometricHandlerProvider, (fqName) -> mDaemon, false /* resetLockoutRequiresChallenge */, false /* testHalEnabled */); waitForIdle(); } @Test Loading Loading @@ -181,7 +190,8 @@ public class FaceProviderTest { mFaceProvider = new FaceProvider(mContext, mBiometricStateCallback, mAuthenticationStateListeners, hidlFaceSensorConfig, TAG, mLockoutResetDispatcher, mBiometricContext, mDaemon, mBiometricHandlerProvider, true /* resetLockoutRequiresChallenge */, mBiometricHandlerProvider, (fqName) -> mDaemon, true /* resetLockoutRequiresChallenge */, true /* testHalEnabled */); assertThat(mFaceProvider.mFaceSensors.get(faceId) Loading Loading @@ -283,6 +293,30 @@ public class FaceProviderTest { anyBoolean()); } @Test @RequiresFlagsEnabled(Flags.FLAG_INTERNAL_CLEANUP_FOR_ALL_PROFILES) public void testGetHalInstance_whenDaemonIsNull() { mFaceProvider.setTestHalEnabled(false); for (SensorProps sensor: mSensorProps) { mFaceProvider.mFaceSensors.get(sensor.commonProps.sensorId).setScheduler(mScheduler); } //Reset value of FaceProvider#mDaemon mFaceProvider.binderDied(); waitForIdle(); final IFace daemon = mFaceProvider.getHalInstance(); waitForIdle(); assertNotNull(daemon); verify(mScheduler, times(ALIVE_USERS.size() * mSensorProps.length)) .scheduleClientMonitor(any(FaceInternalCleanupClient.class), any(ClientMonitorCallback.class)); verify(mScheduler, times(ALIVE_USERS.size() * mSensorProps.length)) .scheduleClientMonitor(any(FaceGetAuthenticatorIdClient.class)); } private void waitForIdle() { mLooper.dispatchAll(); } Loading
services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java +44 −4 Original line number Diff line number Diff line Loading @@ -34,7 +34,9 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.content.Context; import android.content.pm.UserInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.hardware.biometrics.IBiometricSensorReceiver; Loading @@ -52,12 +54,14 @@ import android.os.RemoteException; import android.os.UserManager; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.filters.SmallTest; import com.android.server.biometrics.BiometricHandlerProvider; import com.android.server.biometrics.Flags; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.sensors.AuthSessionCoordinator; import com.android.server.biometrics.sensors.AuthenticationStateListeners; Loading @@ -78,13 +82,16 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; @Presubmit @SmallTest public class FingerprintProviderTest { private static final String TAG = "FingerprintProviderTest"; private static final int CURRENT_USER_ID = ActivityManager.getCurrentUser(); private static final List<Integer> ALIVE_USERS = List.of(CURRENT_USER_ID, CURRENT_USER_ID + 1, CURRENT_USER_ID + 2); @Rule public final CheckFlagsRule mCheckFlagsRule = Loading Loading @@ -116,6 +123,8 @@ public class FingerprintProviderTest { private AuthSessionCoordinator mAuthSessionCoordinator; @Mock private BiometricScheduler<IFingerprint, ISession> mScheduler; @Mock private IBinder mBinder; private final TestLooper mLooper = new TestLooper(); Loading @@ -130,8 +139,10 @@ public class FingerprintProviderTest { when(mContext.getResources()).thenReturn(mResources); when(mResources.obtainTypedArray(anyInt())).thenReturn(mock(TypedArray.class)); when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>()); when(mUserManager.getAliveUsers()).thenReturn( ALIVE_USERS.stream().map(i -> new UserInfo(i, "", 0)).toList()); when(mDaemon.createSession(anyInt(), anyInt(), any())).thenReturn(mock(ISession.class)); when(mDaemon.asBinder()).thenReturn(mBinder); when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator); when(mBiometricHandlerProvider.getBiometricCallbackHandler()).thenReturn( mBiometricCallbackHandler); Loading @@ -154,8 +165,10 @@ public class FingerprintProviderTest { mFingerprintProvider = new FingerprintProvider(mContext, mBiometricStateCallback, mAuthenticationStateListeners, mSensorProps, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext, mDaemon, mBiometricHandlerProvider, mDaemon, mBiometricHandlerProvider, (fqName) -> mDaemon, false /* resetLockoutRequiresHardwareAuthToken */, true /* testHalEnabled */); waitForIdle(); } @Test Loading Loading @@ -187,6 +200,7 @@ public class FingerprintProviderTest { hidlFingerprintSensorConfigs, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext, mDaemon, mBiometricHandlerProvider, (fqName) -> mDaemon, false /* resetLockoutRequiresHardwareAuthToken */, true /* testHalEnabled */); Loading Loading @@ -301,7 +315,7 @@ public class FingerprintProviderTest { mFingerprintProvider = new FingerprintProvider(mContext, mBiometricStateCallback, mAuthenticationStateListeners, mSensorProps, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext, mDaemon, mBiometricHandlerProvider, mDaemon, mBiometricHandlerProvider, (fqName) -> mDaemon, false /* resetLockoutRequiresHardwareAuthToken */, true /* testHalEnabled */); waitForIdle(); Loading @@ -313,6 +327,32 @@ public class FingerprintProviderTest { verify(mFingerprintHandler).sendMessageDelayed(any(), anyLong()); } @Test @RequiresFlagsEnabled(Flags.FLAG_INTERNAL_CLEANUP_FOR_ALL_PROFILES) public void testGetHalInstance_whenDaemonIsNull() { mFingerprintProvider.setTestHalEnabled(false); for (SensorProps sensor : mSensorProps) { mFingerprintProvider.mFingerprintSensors.get(sensor.commonProps.sensorId).setScheduler( mScheduler); } //Reset value of FingerprintProvider#mDaemon mFingerprintProvider.binderDied(); waitForIdle(); final IFingerprint daemon = mFingerprintProvider.getHalInstance(); waitForIdle(); assertNotNull(daemon); verify(mScheduler, times(ALIVE_USERS.size() * mSensorProps.length)) .scheduleClientMonitor(any(FingerprintInternalCleanupClient.class), any(ClientMonitorCallback.class)); verify(mScheduler, times(ALIVE_USERS.size() * mSensorProps.length)) .scheduleClientMonitor(any(FingerprintGetAuthenticatorIdClient.class)); } private void waitForIdle() { mLooper.dispatchAll(); } Loading