Loading services/core/java/com/android/server/trust/TrustManagerService.java +7 −0 Original line number Diff line number Diff line Loading @@ -1442,6 +1442,13 @@ public class TrustManagerService extends SystemService { if (biometricManager == null) { return new long[0]; } if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2() && mLockPatternUtils.isProfileWithUnifiedChallenge(userId)) { // Profiles with unified challenge have their own set of biometrics, but the device // unlock happens via the parent user. In this case Keystore needs to be given the list // of biometric SIDs from the parent user, not the profile. userId = resolveProfileParent(userId); } return biometricManager.getAuthenticatorIds(userId); } Loading services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java +95 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static com.google.common.truth.Truth.assertThat; import android.Manifest; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.IActivityManager; import android.app.admin.DevicePolicyManager; import android.app.trust.ITrustListener; import android.app.trust.ITrustManager; Loading @@ -45,7 +46,9 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; Loading @@ -53,7 +56,12 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.security.Authorization; import android.security.authorization.IKeystoreAuthorization; import android.service.trust.TrustAgentService; import android.testing.TestableContext; import android.view.IWindowManager; Loading Loading @@ -83,23 +91,34 @@ public class TrustManagerServiceTest { @Rule public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) .spyStatic(ActivityManager.class) .spyStatic(Authorization.class) .mockStatic(ServiceManager.class) .mockStatic(WindowManagerGlobal.class) .build(); @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Rule public final MockContext mMockContext = new MockContext( ApplicationProvider.getApplicationContext()); private static final String URI_SCHEME_PACKAGE = "package"; private static final int TEST_USER_ID = 50; private static final int PARENT_USER_ID = 60; private static final int PROFILE_USER_ID = 70; private static final long[] PARENT_BIOMETRIC_SIDS = new long[] { 600L, 601L }; private static final long[] PROFILE_BIOMETRIC_SIDS = new long[] { 700L, 701L }; private final ArrayList<ResolveInfo> mTrustAgentResolveInfoList = new ArrayList<>(); private final ArrayList<ComponentName> mKnownTrustAgents = new ArrayList<>(); private final ArrayList<ComponentName> mEnabledTrustAgents = new ArrayList<>(); private @Mock ActivityManager mActivityManager; private @Mock BiometricManager mBiometricManager; private @Mock DevicePolicyManager mDevicePolicyManager; private @Mock IKeystoreAuthorization mKeystoreAuthorization; private @Mock LockPatternUtils mLockPatternUtils; private @Mock PackageManager mPackageManager; private @Mock UserManager mUserManager; Loading @@ -113,6 +132,9 @@ public class TrustManagerServiceTest { @Before public void setUp() throws Exception { when(mActivityManager.isUserRunning(TEST_USER_ID)).thenReturn(true); doReturn(mock(IActivityManager.class)).when(() -> ActivityManager.getService()); doReturn(mKeystoreAuthorization).when(() -> Authorization.getService()); when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager); when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); Loading Loading @@ -146,6 +168,7 @@ public class TrustManagerServiceTest { when(mWindowManager.isKeyguardLocked()).thenReturn(true); mMockContext.addMockSystemService(ActivityManager.class, mActivityManager); mMockContext.addMockSystemService(BiometricManager.class, mBiometricManager); mMockContext.setMockPackageManager(mPackageManager); mMockContext.addMockSystemService(UserManager.class, mUserManager); doReturn(mWindowManager).when(() -> WindowManagerGlobal.getWindowManagerService()); Loading Loading @@ -322,6 +345,73 @@ public class TrustManagerServiceTest { verify(trustListener).onEnabledTrustAgentsChanged(TEST_USER_ID); } // Tests that when the device is locked for a managed profile with a *unified* challenge, the // device locked notification that is sent to Keystore contains the biometric SIDs of the parent // user, not the profile. This matches the authentication that is needed to unlock the device // for the profile again. @Test @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) public void testLockDeviceForManagedProfileWithUnifiedChallenge_usesParentBiometricSids() throws Exception { setupMocksForProfile(/* unifiedChallenge= */ true); when(mWindowManager.isKeyguardLocked()).thenReturn(false); mTrustManager.reportKeyguardShowingChanged(); verify(mKeystoreAuthorization).onDeviceUnlocked(PARENT_USER_ID, null); verify(mKeystoreAuthorization).onDeviceUnlocked(PROFILE_USER_ID, null); when(mWindowManager.isKeyguardLocked()).thenReturn(true); mTrustManager.reportKeyguardShowingChanged(); verify(mKeystoreAuthorization) .onDeviceLocked(eq(PARENT_USER_ID), eq(PARENT_BIOMETRIC_SIDS)); verify(mKeystoreAuthorization) .onDeviceLocked(eq(PROFILE_USER_ID), eq(PARENT_BIOMETRIC_SIDS)); } // Tests that when the device is locked for a managed profile with a *separate* challenge, the // device locked notification that is sent to Keystore contains the biometric SIDs of the // profile itself. This matches the authentication that is needed to unlock the device for the // profile again. @Test public void testLockDeviceForManagedProfileWithSeparateChallenge_usesProfileBiometricSids() throws Exception { setupMocksForProfile(/* unifiedChallenge= */ false); mTrustManager.setDeviceLockedForUser(PROFILE_USER_ID, false); verify(mKeystoreAuthorization).onDeviceUnlocked(PROFILE_USER_ID, null); mTrustManager.setDeviceLockedForUser(PROFILE_USER_ID, true); verify(mKeystoreAuthorization) .onDeviceLocked(eq(PROFILE_USER_ID), eq(PROFILE_BIOMETRIC_SIDS)); } private void setupMocksForProfile(boolean unifiedChallenge) { UserInfo parent = new UserInfo(PARENT_USER_ID, "parent", UserInfo.FLAG_FULL); UserInfo profile = new UserInfo(PROFILE_USER_ID, "profile", UserInfo.FLAG_MANAGED_PROFILE); when(mUserManager.getAliveUsers()).thenReturn(List.of(parent, profile)); when(mUserManager.getUserInfo(PARENT_USER_ID)).thenReturn(parent); when(mUserManager.getUserInfo(PROFILE_USER_ID)).thenReturn(profile); when(mUserManager.getProfileParent(PROFILE_USER_ID)).thenReturn(parent); when(mUserManager.getEnabledProfileIds(PARENT_USER_ID)) .thenReturn(new int[] { PROFILE_USER_ID }); when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); when(mLockPatternUtils.isProfileWithUnifiedChallenge(PROFILE_USER_ID)) .thenReturn(unifiedChallenge); when(mLockPatternUtils.isManagedProfileWithUnifiedChallenge(PROFILE_USER_ID)) .thenReturn(unifiedChallenge); when(mLockPatternUtils.isSeparateProfileChallengeEnabled(PROFILE_USER_ID)) .thenReturn(!unifiedChallenge); when(mBiometricManager.getAuthenticatorIds(PARENT_USER_ID)) .thenReturn(PARENT_BIOMETRIC_SIDS); when(mBiometricManager.getAuthenticatorIds(PROFILE_USER_ID)) .thenReturn(PROFILE_BIOMETRIC_SIDS); bootService(); mService.onUserSwitching(null, new SystemService.TargetUser(parent)); } private void addTrustAgent(ComponentName agentComponentName, boolean isSystemApp) { ApplicationInfo applicationInfo = new ApplicationInfo(); if (isSystemApp) { Loading Loading @@ -378,6 +468,11 @@ public class TrustManagerServiceTest { scheduler); } @Override public void sendBroadcastAsUser(Intent intent, UserHandle user, @Nullable String receiverPermission, @Nullable Bundle options) { } void sendPackageChangedBroadcast(ComponentName changedComponent) { Intent intent = new Intent( Intent.ACTION_PACKAGE_CHANGED, Loading Loading
services/core/java/com/android/server/trust/TrustManagerService.java +7 −0 Original line number Diff line number Diff line Loading @@ -1442,6 +1442,13 @@ public class TrustManagerService extends SystemService { if (biometricManager == null) { return new long[0]; } if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2() && mLockPatternUtils.isProfileWithUnifiedChallenge(userId)) { // Profiles with unified challenge have their own set of biometrics, but the device // unlock happens via the parent user. In this case Keystore needs to be given the list // of biometric SIDs from the parent user, not the profile. userId = resolveProfileParent(userId); } return biometricManager.getAuthenticatorIds(userId); } Loading
services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java +95 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static com.google.common.truth.Truth.assertThat; import android.Manifest; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.IActivityManager; import android.app.admin.DevicePolicyManager; import android.app.trust.ITrustListener; import android.app.trust.ITrustManager; Loading @@ -45,7 +46,9 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; Loading @@ -53,7 +56,12 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.security.Authorization; import android.security.authorization.IKeystoreAuthorization; import android.service.trust.TrustAgentService; import android.testing.TestableContext; import android.view.IWindowManager; Loading Loading @@ -83,23 +91,34 @@ public class TrustManagerServiceTest { @Rule public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) .spyStatic(ActivityManager.class) .spyStatic(Authorization.class) .mockStatic(ServiceManager.class) .mockStatic(WindowManagerGlobal.class) .build(); @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Rule public final MockContext mMockContext = new MockContext( ApplicationProvider.getApplicationContext()); private static final String URI_SCHEME_PACKAGE = "package"; private static final int TEST_USER_ID = 50; private static final int PARENT_USER_ID = 60; private static final int PROFILE_USER_ID = 70; private static final long[] PARENT_BIOMETRIC_SIDS = new long[] { 600L, 601L }; private static final long[] PROFILE_BIOMETRIC_SIDS = new long[] { 700L, 701L }; private final ArrayList<ResolveInfo> mTrustAgentResolveInfoList = new ArrayList<>(); private final ArrayList<ComponentName> mKnownTrustAgents = new ArrayList<>(); private final ArrayList<ComponentName> mEnabledTrustAgents = new ArrayList<>(); private @Mock ActivityManager mActivityManager; private @Mock BiometricManager mBiometricManager; private @Mock DevicePolicyManager mDevicePolicyManager; private @Mock IKeystoreAuthorization mKeystoreAuthorization; private @Mock LockPatternUtils mLockPatternUtils; private @Mock PackageManager mPackageManager; private @Mock UserManager mUserManager; Loading @@ -113,6 +132,9 @@ public class TrustManagerServiceTest { @Before public void setUp() throws Exception { when(mActivityManager.isUserRunning(TEST_USER_ID)).thenReturn(true); doReturn(mock(IActivityManager.class)).when(() -> ActivityManager.getService()); doReturn(mKeystoreAuthorization).when(() -> Authorization.getService()); when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager); when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); Loading Loading @@ -146,6 +168,7 @@ public class TrustManagerServiceTest { when(mWindowManager.isKeyguardLocked()).thenReturn(true); mMockContext.addMockSystemService(ActivityManager.class, mActivityManager); mMockContext.addMockSystemService(BiometricManager.class, mBiometricManager); mMockContext.setMockPackageManager(mPackageManager); mMockContext.addMockSystemService(UserManager.class, mUserManager); doReturn(mWindowManager).when(() -> WindowManagerGlobal.getWindowManagerService()); Loading Loading @@ -322,6 +345,73 @@ public class TrustManagerServiceTest { verify(trustListener).onEnabledTrustAgentsChanged(TEST_USER_ID); } // Tests that when the device is locked for a managed profile with a *unified* challenge, the // device locked notification that is sent to Keystore contains the biometric SIDs of the parent // user, not the profile. This matches the authentication that is needed to unlock the device // for the profile again. @Test @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) public void testLockDeviceForManagedProfileWithUnifiedChallenge_usesParentBiometricSids() throws Exception { setupMocksForProfile(/* unifiedChallenge= */ true); when(mWindowManager.isKeyguardLocked()).thenReturn(false); mTrustManager.reportKeyguardShowingChanged(); verify(mKeystoreAuthorization).onDeviceUnlocked(PARENT_USER_ID, null); verify(mKeystoreAuthorization).onDeviceUnlocked(PROFILE_USER_ID, null); when(mWindowManager.isKeyguardLocked()).thenReturn(true); mTrustManager.reportKeyguardShowingChanged(); verify(mKeystoreAuthorization) .onDeviceLocked(eq(PARENT_USER_ID), eq(PARENT_BIOMETRIC_SIDS)); verify(mKeystoreAuthorization) .onDeviceLocked(eq(PROFILE_USER_ID), eq(PARENT_BIOMETRIC_SIDS)); } // Tests that when the device is locked for a managed profile with a *separate* challenge, the // device locked notification that is sent to Keystore contains the biometric SIDs of the // profile itself. This matches the authentication that is needed to unlock the device for the // profile again. @Test public void testLockDeviceForManagedProfileWithSeparateChallenge_usesProfileBiometricSids() throws Exception { setupMocksForProfile(/* unifiedChallenge= */ false); mTrustManager.setDeviceLockedForUser(PROFILE_USER_ID, false); verify(mKeystoreAuthorization).onDeviceUnlocked(PROFILE_USER_ID, null); mTrustManager.setDeviceLockedForUser(PROFILE_USER_ID, true); verify(mKeystoreAuthorization) .onDeviceLocked(eq(PROFILE_USER_ID), eq(PROFILE_BIOMETRIC_SIDS)); } private void setupMocksForProfile(boolean unifiedChallenge) { UserInfo parent = new UserInfo(PARENT_USER_ID, "parent", UserInfo.FLAG_FULL); UserInfo profile = new UserInfo(PROFILE_USER_ID, "profile", UserInfo.FLAG_MANAGED_PROFILE); when(mUserManager.getAliveUsers()).thenReturn(List.of(parent, profile)); when(mUserManager.getUserInfo(PARENT_USER_ID)).thenReturn(parent); when(mUserManager.getUserInfo(PROFILE_USER_ID)).thenReturn(profile); when(mUserManager.getProfileParent(PROFILE_USER_ID)).thenReturn(parent); when(mUserManager.getEnabledProfileIds(PARENT_USER_ID)) .thenReturn(new int[] { PROFILE_USER_ID }); when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); when(mLockPatternUtils.isProfileWithUnifiedChallenge(PROFILE_USER_ID)) .thenReturn(unifiedChallenge); when(mLockPatternUtils.isManagedProfileWithUnifiedChallenge(PROFILE_USER_ID)) .thenReturn(unifiedChallenge); when(mLockPatternUtils.isSeparateProfileChallengeEnabled(PROFILE_USER_ID)) .thenReturn(!unifiedChallenge); when(mBiometricManager.getAuthenticatorIds(PARENT_USER_ID)) .thenReturn(PARENT_BIOMETRIC_SIDS); when(mBiometricManager.getAuthenticatorIds(PROFILE_USER_ID)) .thenReturn(PROFILE_BIOMETRIC_SIDS); bootService(); mService.onUserSwitching(null, new SystemService.TargetUser(parent)); } private void addTrustAgent(ComponentName agentComponentName, boolean isSystemApp) { ApplicationInfo applicationInfo = new ApplicationInfo(); if (isSystemApp) { Loading Loading @@ -378,6 +468,11 @@ public class TrustManagerServiceTest { scheduler); } @Override public void sendBroadcastAsUser(Intent intent, UserHandle user, @Nullable String receiverPermission, @Nullable Bundle options) { } void sendPackageChangedBroadcast(ComponentName changedComponent) { Intent intent = new Intent( Intent.ACTION_PACKAGE_CHANGED, Loading