summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Eric Biggers <ebiggers@google.com> 2024-01-08 20:59:17 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2024-01-08 20:59:17 +0000
commit4b7074b9ad5bb8d44d3b4aeb4b54e135a882e408 (patch)
tree45a5fed59bb4fd72607c8093fc32915326d0f9d7
parentf839d892844da236e8bf669953c7ad4b0267a1dd (diff)
parentfa2d2b742168200370af25f3f87af97bdce344cb (diff)
Merge "Fix UnlockedDeviceRequired with biometric unlock with unified challenge" into main am: f3a6dcf1d7 am: 6aa86d6610 am: fa2d2b7421
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2878769 Change-Id: I0668bcc22e85550e9469d624fb354c9ee98557a5 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java7
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java95
2 files changed, 102 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 5c603c2238bd..5d716fc46f7a 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1440,6 +1440,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);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
index c42c735e3c9d..97e94e3c6fc9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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);
@@ -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());
@@ -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) {
@@ -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,