Loading core/java/android/content/pm/multiuser.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -122,3 +122,10 @@ flag { description: "Handle listing of private space apps in settings pages with interleaved content" bug: "323212460" } flag { name: "enable_hiding_profiles" namespace: "profile_experiences" description: "Allow the use of a profileApiAvailability user property to exclude HIDDEN profiles in API results" bug: "316362775" } core/java/android/os/IUserManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -150,4 +150,5 @@ interface IUserManager { void setBootUser(int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS})") int getBootUser(); int[] getProfileIdsExcludingHidden(int userId, boolean enabledOnly); } core/java/android/os/UserManager.java +19 −0 Original line number Diff line number Diff line Loading @@ -5356,6 +5356,25 @@ public class UserManager { return getProfileIds(userId, true /* enabledOnly */); } /** * @return A list of ids of profiles associated with the specified user excluding those with * {@link UserProperties#getProfileApiVisibility()} set to hidden. The returned list includes * the user itself. * @hide * @see #getProfileIds(int, boolean) */ @RequiresPermission(anyOf = { Manifest.permission.MANAGE_USERS, Manifest.permission.CREATE_USERS, Manifest.permission.QUERY_USERS}, conditional = true) public int[] getProfileIdsExcludingHidden(@UserIdInt int userId, boolean enabled) { try { return mService.getProfileIdsExcludingHidden(userId, enabled); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** * Returns the device credential owner id of the profile from * which this method is called, or userId if called from a user that Loading services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +11 −5 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.UserProperties; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; Loading Loading @@ -268,7 +269,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private boolean canRequestInteractAcrossProfilesUnchecked(String packageName) { final int callingUserId = mInjector.getCallingUserId(); final int[] enabledProfileIds = mInjector.getUserManager().getEnabledProfileIds(callingUserId); mInjector.getUserManager().getProfileIdsExcludingHidden( callingUserId, /* enabled= */ true); if (enabledProfileIds.length < 2) { return false; } Loading Loading @@ -350,7 +352,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { String packageName, @UserIdInt int userId) { return mInjector.withCleanCallingIdentity(() -> { final int[] enabledProfileIds = mInjector.getUserManager().getEnabledProfileIds(userId); mInjector.getUserManager().getProfileIdsExcludingHidden(userId, /* enabled= */ true); List<UserHandle> targetProfiles = new ArrayList<>(); for (final int profileId : enabledProfileIds) { Loading Loading @@ -466,7 +469,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { return; } final int[] profileIds = mInjector.getUserManager().getProfileIds(userId, /* enabledOnly= */ false); mInjector.getUserManager().getProfileIdsExcludingHidden(userId, /* enabled= */ false); for (int profileId : profileIds) { if (!isPackageInstalled(packageName, profileId)) { continue; Loading Loading @@ -632,7 +636,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private boolean canUserAttemptToConfigureInteractAcrossProfiles( String packageName, @UserIdInt int userId) { final int[] profileIds = mInjector.getUserManager().getProfileIds(userId, /* enabledOnly= */ false); mInjector.getUserManager().getProfileIdsExcludingHidden(userId, /* enabled= */ false); if (profileIds.length < 2) { return false; } Loading Loading @@ -676,7 +681,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private boolean hasOtherProfileWithPackageInstalled(String packageName, @UserIdInt int userId) { return mInjector.withCleanCallingIdentity(() -> { final int[] profileIds = mInjector.getUserManager().getProfileIds(userId, /* enabledOnly= */ false); mInjector.getUserManager().getProfileIdsExcludingHidden(userId, /* enabled= */ false); for (int profileId : profileIds) { if (profileId != userId && isPackageInstalled(packageName, profileId)) { return true; Loading services/core/java/com/android/server/pm/UserManagerService.java +37 −8 Original line number Diff line number Diff line Loading @@ -1385,7 +1385,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public int[] getProfileIds(@UserIdInt int userId, boolean enabledOnly) { return getProfileIds(userId, null, enabledOnly); return getProfileIds(userId, null, enabledOnly, /* excludeHidden */ false); } // TODO(b/142482943): Probably @Override and make this accessible in UserManager. Loading @@ -1397,14 +1397,14 @@ public class UserManagerService extends IUserManager.Stub { * If enabledOnly, only returns users that are not {@link UserInfo#FLAG_DISABLED}. */ public int[] getProfileIds(@UserIdInt int userId, @Nullable String userType, boolean enabledOnly) { boolean enabledOnly, boolean excludeHidden) { if (userId != UserHandle.getCallingUserId()) { checkQueryOrCreateUsersPermission("getting profiles related to user " + userId); } final long ident = Binder.clearCallingIdentity(); try { synchronized (mUsersLock) { return getProfileIdsLU(userId, userType, enabledOnly).toArray(); return getProfileIdsLU(userId, userType, enabledOnly, excludeHidden).toArray(); } } finally { Binder.restoreCallingIdentity(ident); Loading @@ -1415,7 +1415,8 @@ public class UserManagerService extends IUserManager.Stub { @GuardedBy("mUsersLock") private List<UserInfo> getProfilesLU(@UserIdInt int userId, @Nullable String userType, boolean enabledOnly, boolean fullInfo) { IntArray profileIds = getProfileIdsLU(userId, userType, enabledOnly); IntArray profileIds = getProfileIdsLU(userId, userType, enabledOnly, /* excludeHidden */ false); ArrayList<UserInfo> users = new ArrayList<>(profileIds.size()); for (int i = 0; i < profileIds.size(); i++) { int profileId = profileIds.get(i); Loading @@ -1440,7 +1441,7 @@ public class UserManagerService extends IUserManager.Stub { */ @GuardedBy("mUsersLock") private IntArray getProfileIdsLU(@UserIdInt int userId, @Nullable String userType, boolean enabledOnly) { boolean enabledOnly, boolean excludeHidden) { UserInfo user = getUserInfoLU(userId); IntArray result = new IntArray(mUsers.size()); if (user == null) { Loading @@ -1465,11 +1466,36 @@ public class UserManagerService extends IUserManager.Stub { if (userType != null && !userType.equals(profile.userType)) { continue; } if (excludeHidden && isProfileHidden(userId)) { continue; } result.add(profile.id); } return result; } /* * Returns all the users that are in the same profile group as userId excluding those with * {@link UserProperties#getProfileApiVisibility()} set to hidden. The returned list includes * the user itself. */ // TODO (b/323011770): Add a permission check to make an exception for App stores if we end // up supporting Private Space on COPE devices @Override public int[] getProfileIdsExcludingHidden(@UserIdInt int userId, boolean enabledOnly) { return getProfileIds(userId, null, enabledOnly, /* excludeHidden */ true); } private boolean isProfileHidden(int userId) { UserProperties userProperties = getUserPropertiesCopy(userId); if (android.os.Flags.allowPrivateProfile() && android.multiuser.Flags.enableHidingProfiles()) { return userProperties.getProfileApiVisibility() == UserProperties.PROFILE_API_VISIBILITY_HIDDEN; } return false; } @Override public int getCredentialOwnerProfile(@UserIdInt int userId) { checkManageUsersPermission("get the credential owner"); Loading Loading @@ -3630,7 +3656,8 @@ public class UserManagerService extends IUserManager.Stub { return 0; } final int userTypeCount = getProfileIds(userId, userType, false).length; final int userTypeCount = getProfileIds(userId, userType, false, /* excludeHidden */ false).length; final int profilesRemovedCount = userTypeCount > 0 && allowedToRemoveOne ? 1 : 0; final int usersCountAfterRemoving = getAliveUsersExcludingGuestsCountLU() - profilesRemovedCount; Loading Loading @@ -5931,7 +5958,8 @@ public class UserManagerService extends IUserManager.Stub { } userData = mUsers.get(userId); isProfile = userData.info.isProfile(); profileIds = isProfile ? null : getProfileIdsLU(userId, null, false); profileIds = isProfile ? null : getProfileIdsLU(userId, null, false, /* excludeHidden */ false); } if (!isProfile) { Loading Loading @@ -7458,7 +7486,8 @@ public class UserManagerService extends IUserManager.Stub { @Override public @NonNull int[] getProfileIds(@UserIdInt int userId, boolean enabledOnly) { synchronized (mUsersLock) { return getProfileIdsLU(userId, null /* userType */, enabledOnly).toArray(); return getProfileIdsLU(userId, null /* userType */, enabledOnly, /* excludeHidden */ false).toArray(); } } Loading Loading
core/java/android/content/pm/multiuser.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -122,3 +122,10 @@ flag { description: "Handle listing of private space apps in settings pages with interleaved content" bug: "323212460" } flag { name: "enable_hiding_profiles" namespace: "profile_experiences" description: "Allow the use of a profileApiAvailability user property to exclude HIDDEN profiles in API results" bug: "316362775" }
core/java/android/os/IUserManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -150,4 +150,5 @@ interface IUserManager { void setBootUser(int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS})") int getBootUser(); int[] getProfileIdsExcludingHidden(int userId, boolean enabledOnly); }
core/java/android/os/UserManager.java +19 −0 Original line number Diff line number Diff line Loading @@ -5356,6 +5356,25 @@ public class UserManager { return getProfileIds(userId, true /* enabledOnly */); } /** * @return A list of ids of profiles associated with the specified user excluding those with * {@link UserProperties#getProfileApiVisibility()} set to hidden. The returned list includes * the user itself. * @hide * @see #getProfileIds(int, boolean) */ @RequiresPermission(anyOf = { Manifest.permission.MANAGE_USERS, Manifest.permission.CREATE_USERS, Manifest.permission.QUERY_USERS}, conditional = true) public int[] getProfileIdsExcludingHidden(@UserIdInt int userId, boolean enabled) { try { return mService.getProfileIdsExcludingHidden(userId, enabled); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** * Returns the device credential owner id of the profile from * which this method is called, or userId if called from a user that Loading
services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +11 −5 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.UserProperties; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; Loading Loading @@ -268,7 +269,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private boolean canRequestInteractAcrossProfilesUnchecked(String packageName) { final int callingUserId = mInjector.getCallingUserId(); final int[] enabledProfileIds = mInjector.getUserManager().getEnabledProfileIds(callingUserId); mInjector.getUserManager().getProfileIdsExcludingHidden( callingUserId, /* enabled= */ true); if (enabledProfileIds.length < 2) { return false; } Loading Loading @@ -350,7 +352,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { String packageName, @UserIdInt int userId) { return mInjector.withCleanCallingIdentity(() -> { final int[] enabledProfileIds = mInjector.getUserManager().getEnabledProfileIds(userId); mInjector.getUserManager().getProfileIdsExcludingHidden(userId, /* enabled= */ true); List<UserHandle> targetProfiles = new ArrayList<>(); for (final int profileId : enabledProfileIds) { Loading Loading @@ -466,7 +469,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { return; } final int[] profileIds = mInjector.getUserManager().getProfileIds(userId, /* enabledOnly= */ false); mInjector.getUserManager().getProfileIdsExcludingHidden(userId, /* enabled= */ false); for (int profileId : profileIds) { if (!isPackageInstalled(packageName, profileId)) { continue; Loading Loading @@ -632,7 +636,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private boolean canUserAttemptToConfigureInteractAcrossProfiles( String packageName, @UserIdInt int userId) { final int[] profileIds = mInjector.getUserManager().getProfileIds(userId, /* enabledOnly= */ false); mInjector.getUserManager().getProfileIdsExcludingHidden(userId, /* enabled= */ false); if (profileIds.length < 2) { return false; } Loading Loading @@ -676,7 +681,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private boolean hasOtherProfileWithPackageInstalled(String packageName, @UserIdInt int userId) { return mInjector.withCleanCallingIdentity(() -> { final int[] profileIds = mInjector.getUserManager().getProfileIds(userId, /* enabledOnly= */ false); mInjector.getUserManager().getProfileIdsExcludingHidden(userId, /* enabled= */ false); for (int profileId : profileIds) { if (profileId != userId && isPackageInstalled(packageName, profileId)) { return true; Loading
services/core/java/com/android/server/pm/UserManagerService.java +37 −8 Original line number Diff line number Diff line Loading @@ -1385,7 +1385,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public int[] getProfileIds(@UserIdInt int userId, boolean enabledOnly) { return getProfileIds(userId, null, enabledOnly); return getProfileIds(userId, null, enabledOnly, /* excludeHidden */ false); } // TODO(b/142482943): Probably @Override and make this accessible in UserManager. Loading @@ -1397,14 +1397,14 @@ public class UserManagerService extends IUserManager.Stub { * If enabledOnly, only returns users that are not {@link UserInfo#FLAG_DISABLED}. */ public int[] getProfileIds(@UserIdInt int userId, @Nullable String userType, boolean enabledOnly) { boolean enabledOnly, boolean excludeHidden) { if (userId != UserHandle.getCallingUserId()) { checkQueryOrCreateUsersPermission("getting profiles related to user " + userId); } final long ident = Binder.clearCallingIdentity(); try { synchronized (mUsersLock) { return getProfileIdsLU(userId, userType, enabledOnly).toArray(); return getProfileIdsLU(userId, userType, enabledOnly, excludeHidden).toArray(); } } finally { Binder.restoreCallingIdentity(ident); Loading @@ -1415,7 +1415,8 @@ public class UserManagerService extends IUserManager.Stub { @GuardedBy("mUsersLock") private List<UserInfo> getProfilesLU(@UserIdInt int userId, @Nullable String userType, boolean enabledOnly, boolean fullInfo) { IntArray profileIds = getProfileIdsLU(userId, userType, enabledOnly); IntArray profileIds = getProfileIdsLU(userId, userType, enabledOnly, /* excludeHidden */ false); ArrayList<UserInfo> users = new ArrayList<>(profileIds.size()); for (int i = 0; i < profileIds.size(); i++) { int profileId = profileIds.get(i); Loading @@ -1440,7 +1441,7 @@ public class UserManagerService extends IUserManager.Stub { */ @GuardedBy("mUsersLock") private IntArray getProfileIdsLU(@UserIdInt int userId, @Nullable String userType, boolean enabledOnly) { boolean enabledOnly, boolean excludeHidden) { UserInfo user = getUserInfoLU(userId); IntArray result = new IntArray(mUsers.size()); if (user == null) { Loading @@ -1465,11 +1466,36 @@ public class UserManagerService extends IUserManager.Stub { if (userType != null && !userType.equals(profile.userType)) { continue; } if (excludeHidden && isProfileHidden(userId)) { continue; } result.add(profile.id); } return result; } /* * Returns all the users that are in the same profile group as userId excluding those with * {@link UserProperties#getProfileApiVisibility()} set to hidden. The returned list includes * the user itself. */ // TODO (b/323011770): Add a permission check to make an exception for App stores if we end // up supporting Private Space on COPE devices @Override public int[] getProfileIdsExcludingHidden(@UserIdInt int userId, boolean enabledOnly) { return getProfileIds(userId, null, enabledOnly, /* excludeHidden */ true); } private boolean isProfileHidden(int userId) { UserProperties userProperties = getUserPropertiesCopy(userId); if (android.os.Flags.allowPrivateProfile() && android.multiuser.Flags.enableHidingProfiles()) { return userProperties.getProfileApiVisibility() == UserProperties.PROFILE_API_VISIBILITY_HIDDEN; } return false; } @Override public int getCredentialOwnerProfile(@UserIdInt int userId) { checkManageUsersPermission("get the credential owner"); Loading Loading @@ -3630,7 +3656,8 @@ public class UserManagerService extends IUserManager.Stub { return 0; } final int userTypeCount = getProfileIds(userId, userType, false).length; final int userTypeCount = getProfileIds(userId, userType, false, /* excludeHidden */ false).length; final int profilesRemovedCount = userTypeCount > 0 && allowedToRemoveOne ? 1 : 0; final int usersCountAfterRemoving = getAliveUsersExcludingGuestsCountLU() - profilesRemovedCount; Loading Loading @@ -5931,7 +5958,8 @@ public class UserManagerService extends IUserManager.Stub { } userData = mUsers.get(userId); isProfile = userData.info.isProfile(); profileIds = isProfile ? null : getProfileIdsLU(userId, null, false); profileIds = isProfile ? null : getProfileIdsLU(userId, null, false, /* excludeHidden */ false); } if (!isProfile) { Loading Loading @@ -7458,7 +7486,8 @@ public class UserManagerService extends IUserManager.Stub { @Override public @NonNull int[] getProfileIds(@UserIdInt int userId, boolean enabledOnly) { synchronized (mUsersLock) { return getProfileIdsLU(userId, null /* userType */, enabledOnly).toArray(); return getProfileIdsLU(userId, null /* userType */, enabledOnly, /* excludeHidden */ false).toArray(); } } Loading