diff options
author | 2025-03-07 11:39:54 -0800 | |
---|---|---|
committer | 2025-03-10 14:12:51 -0700 | |
commit | ff2ab4857d942e9e25e36f529b9ecdf6d5b2f93b (patch) | |
tree | ef704da45674025ca76e857f556f3a3c5cab6255 | |
parent | 089efb6b1d10178082a0c65a8b38c5c9bd49b675 (diff) |
Update createConfirmSupervisionCredentialsIntent to return null if the supervising user is not present or does not have secure credentials.
Bug: 392961554
Flag: android.app.supervision.flags.supervision_manager_apis
Test: atest SupervisionServiceTest
Change-Id: Ide3648dc5dc33c57f9093b450d5f762e7f6517d5
4 files changed, 99 insertions, 9 deletions
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java index f88681dbcaeb..e98176b0e82b 100644 --- a/services/core/java/com/android/server/pm/UserManagerInternal.java +++ b/services/core/java/com/android/server/pm/UserManagerInternal.java @@ -18,6 +18,7 @@ package com.android.server.pm; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SpecialUsers.CanBeNULL; import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.LauncherUserInfo; @@ -620,11 +621,17 @@ public abstract class UserManagerInternal { * Returns the user id of the communal profile, or {@link android.os.UserHandle#USER_NULL} * if there is no such user. */ - public abstract @UserIdInt int getCommunalProfileId(); + public abstract @CanBeNULL @UserIdInt int getCommunalProfileId(); /** - * Checks whether to show a notification for sounds (e.g., alarms, timers, etc.) from - * background users. + * Returns the user id of the supervising profile, or {@link android.os.UserHandle#USER_NULL} if + * there is no such user. + */ + public abstract @CanBeNULL @UserIdInt int getSupervisingProfileId(); + + /** + * Checks whether to show a notification for sounds (e.g., alarms, timers, etc.) from background + * users. */ public static boolean shouldShowNotificationForBackgroundUserSounds() { return Flags.addUiForSoundsFromBackgroundUsers() && Resources.getSystem().getBoolean( diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 092ec8ef4a8a..f15cc56d12ad 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1521,6 +1521,20 @@ public class UserManagerService extends IUserManager.Stub { return UserHandle.USER_NULL; } + /** Returns the currently-designated supervising profile, or USER_NULL if not present. */ + private @CanBeNULL @UserIdInt int getSupervisingProfileId() { + synchronized (mUsersLock) { + final int userSize = mUsers.size(); + for (int i = 0; i < userSize; i++) { + final UserInfo user = mUsers.valueAt(i).info; + if (user.isSupervisingProfile() && !mRemovingUserIds.get(user.id)) { + return user.id; + } + } + } + return UserHandle.USER_NULL; + } + public @NonNull List<UserInfo> getUsers(boolean excludeDying) { return getUsers(/*excludePartial= */ true, excludeDying, /* excludePreCreated= */ true); @@ -8335,10 +8349,14 @@ public class UserManagerService extends IUserManager.Stub { } @Override - public @UserIdInt int getCommunalProfileId() { + public @CanBeNULL @UserIdInt int getCommunalProfileId() { return getCommunalProfileIdUnchecked(); } + @Override + public @CanBeNULL @UserIdInt int getSupervisingProfileId() { + return UserManagerService.this.getSupervisingProfileId(); + } } // class LocalService diff --git a/services/supervision/java/com/android/server/supervision/SupervisionService.java b/services/supervision/java/com/android/server/supervision/SupervisionService.java index bb6339c79502..0b5a95b0e888 100644 --- a/services/supervision/java/com/android/server/supervision/SupervisionService.java +++ b/services/supervision/java/com/android/server/supervision/SupervisionService.java @@ -27,6 +27,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.UserIdInt; +import android.app.KeyguardManager; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.supervision.ISupervisionManager; @@ -147,9 +148,21 @@ public class SupervisionService extends ISupervisionManager.Stub { @Override @Nullable public Intent createConfirmSupervisionCredentialsIntent() { - // TODO(b/392961554): (1) Return null if supervision is not enabled. - // (2) check if PIN exists before return a valid intent. enforceAnyPermission(QUERY_USERS, MANAGE_USERS); + if (!isSupervisionEnabledForUser(mContext.getUserId())) { + return null; + } + // Verify the supervising user profile exists and has a secure credential set. + final int supervisingUserId = mInjector.getUserManagerInternal().getSupervisingProfileId(); + final long token = Binder.clearCallingIdentity(); + try { + if (supervisingUserId == UserHandle.USER_NULL + || !mInjector.getKeyguardManager().isDeviceSecure(supervisingUserId)) { + return null; + } + } finally { + Binder.restoreCallingIdentity(token); + } final Intent intent = new Intent(ACTION_CONFIRM_SUPERVISION_CREDENTIALS); // explicitly set the package for security intent.setPackage("com.android.settings"); @@ -277,6 +290,7 @@ public class SupervisionService extends ISupervisionManager.Stub { static class Injector { private final Context mContext; private DevicePolicyManagerInternal mDpmInternal; + private KeyguardManager mKeyguardManager; private PackageManager mPackageManager; private UserManagerInternal mUserManagerInternal; @@ -292,6 +306,13 @@ public class SupervisionService extends ISupervisionManager.Stub { return mDpmInternal; } + KeyguardManager getKeyguardManager() { + if (mKeyguardManager == null) { + mKeyguardManager = mContext.getSystemService(KeyguardManager.class); + } + return mKeyguardManager; + } + PackageManager getPackageManager() { if (mPackageManager == null) { mPackageManager = mContext.getPackageManager(); diff --git a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt index fbf906586e8b..c59f0a05c619 100644 --- a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt +++ b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt @@ -17,6 +17,7 @@ package com.android.server.supervision import android.app.Activity +import android.app.KeyguardManager import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManagerInternal import android.app.supervision.flags.Flags @@ -61,6 +62,9 @@ class SupervisionServiceTest { @get:Rule val mocks: MockitoRule = MockitoJUnit.rule() @Mock private lateinit var mockDpmInternal: DevicePolicyManagerInternal + + @Mock + private lateinit var mockKeyguardManager: KeyguardManager @Mock private lateinit var mockPackageManager: PackageManager @Mock private lateinit var mockUserManagerInternal: UserManagerInternal @@ -71,7 +75,7 @@ class SupervisionServiceTest { @Before fun setUp() { context = InstrumentationRegistry.getInstrumentation().context - context = SupervisionContextWrapper(context, mockPackageManager) + context = SupervisionContextWrapper(context, mockKeyguardManager, mockPackageManager) LocalServices.removeServiceForTest(DevicePolicyManagerInternal::class.java) LocalServices.addService(DevicePolicyManagerInternal::class.java, mockDpmInternal) @@ -250,11 +254,41 @@ class SupervisionServiceTest { @Test fun createConfirmSupervisionCredentialsIntent() { + service.mInternal.setSupervisionEnabledForUser(context.getUserId(), true) + whenever(mockUserManagerInternal.getSupervisingProfileId()).thenReturn(SUPERVISING_USER_ID) + whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(true) + val intent = checkNotNull(service.createConfirmSupervisionCredentialsIntent()) assertThat(intent.action).isEqualTo(ACTION_CONFIRM_SUPERVISION_CREDENTIALS) assertThat(intent.getPackage()).isEqualTo("com.android.settings") } + @Test + fun createConfirmSupervisionCredentialsIntent_supervisionNotEnabled_returnsNull() { + service.mInternal.setSupervisionEnabledForUser(context.getUserId(), false) + whenever(mockUserManagerInternal.getSupervisingProfileId()).thenReturn(SUPERVISING_USER_ID) + whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(true) + + assertThat(service.createConfirmSupervisionCredentialsIntent()).isNull() + } + + @Test + fun createConfirmSupervisionCredentialsIntent_noSupervisingUser_returnsNull() { + service.mInternal.setSupervisionEnabledForUser(context.getUserId(), true) + whenever(mockUserManagerInternal.getSupervisingProfileId()).thenReturn(UserHandle.USER_NULL) + + assertThat(service.createConfirmSupervisionCredentialsIntent()).isNull() + } + + @Test + fun createConfirmSupervisionCredentialsIntent_supervisingUserMissingSecureLock_returnsNull() { + service.mInternal.setSupervisionEnabledForUser(context.getUserId(), true) + whenever(mockUserManagerInternal.getSupervisingProfileId()).thenReturn(SUPERVISING_USER_ID) + whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(false) + + assertThat(service.createConfirmSupervisionCredentialsIntent()).isNull() + } + private val systemSupervisionPackage: String get() = context.getResources().getString(R.string.config_systemSupervision) @@ -279,6 +313,7 @@ class SupervisionServiceTest { private companion object { const val USER_ID = 100 const val APP_UID = USER_ID * UserHandle.PER_USER_RANGE + const val SUPERVISING_USER_ID = 10 } } @@ -286,10 +321,19 @@ class SupervisionServiceTest { * A context wrapper that allows broadcast intents to immediately invoke the receivers without * performing checks on the sending user. */ -private class SupervisionContextWrapper(val context: Context, val pkgManager: PackageManager) : - ContextWrapper(context) { +private class SupervisionContextWrapper( + val context: Context, + val keyguardManager: KeyguardManager, + val pkgManager: PackageManager, +) : ContextWrapper(context) { val interceptors = mutableListOf<Pair<BroadcastReceiver, IntentFilter>>() + override fun getSystemService(name: String): Any = + when (name) { + Context.KEYGUARD_SERVICE -> keyguardManager + else -> super.getSystemService(name) + } + override fun getPackageManager() = pkgManager override fun registerReceiverForAllUsers( |