Cache getProfileIds to reduce high volume of binder calls.
This CL introduce 2 caches one for enabled profiles only other
for disabled profiles. This diffrention is, so additional boolean
parameter required by server is cached.
Alternatively caching could be done by introducing wrapper method
which takes pair object combining both parameters.
Test: atest UserManagerTest
Flag: android.multiuser.cache_profile_ids_read_only
Bug: 350421409
Change-Id: Ib0594d8dd3f4c0d8576bf7c130fb7a017408a76d
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index fa99f35..4bc8fe0 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -5502,10 +5502,14 @@
Manifest.permission.CREATE_USERS,
Manifest.permission.QUERY_USERS}, conditional = true)
public @NonNull int[] getProfileIds(@UserIdInt int userId, boolean enabledOnly) {
- try {
- return mService.getProfileIds(userId, enabledOnly);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
+ if (android.multiuser.Flags.cacheProfileIdsReadOnly()) {
+ return enabledOnly ? getEnabledProfileIds(userId) : getProfileIdsWithDisabled(userId);
+ } else {
+ try {
+ return mService.getProfileIds(userId, enabledOnly);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
}
}
@@ -5518,8 +5522,14 @@
Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS,
Manifest.permission.QUERY_USERS}, conditional = true)
+ @CachedProperty(api = "user_manager_users")
public int[] getProfileIdsWithDisabled(@UserIdInt int userId) {
- return getProfileIds(userId, false /* enabledOnly */);
+ if (android.multiuser.Flags.cacheProfileIdsReadOnly()) {
+ return UserManagerCache.getProfileIdsWithDisabled(
+ (Integer userIdentifuer) -> mService.getProfileIds(userIdentifuer, false), userId);
+ } else {
+ return getProfileIds(userId, false /* enabledOnly */);
+ }
}
/**
@@ -5530,8 +5540,21 @@
Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS,
Manifest.permission.QUERY_USERS}, conditional = true)
+ @CachedProperty(api = "user_manager_users_enabled")
public int[] getEnabledProfileIds(@UserIdInt int userId) {
- return getProfileIds(userId, true /* enabledOnly */);
+ if (android.multiuser.Flags.cacheProfileIdsReadOnly()) {
+ return UserManagerCache.getEnabledProfileIds(
+ (Integer userIdentifuer) -> mService.getProfileIds(userIdentifuer, true), userId);
+ } else {
+ return getProfileIds(userId, true /* enabledOnly */);
+ }
+ }
+
+ /** @hide */
+ public static final void invalidateEnabledProfileIds() {
+ if (android.multiuser.Flags.cacheProfileIdsReadOnly()) {
+ UserManagerCache.invalidateEnabledProfileIds();
+ }
}
/**
@@ -6443,6 +6466,21 @@
if (android.multiuser.Flags.cacheProfileParentReadOnly()) {
UserManagerCache.invalidateProfileParent();
}
+ invalidateEnabledProfileIds();
+ }
+
+ /**
+ * Invalidate caches when related to specific user info flags change.
+ *
+ * @param flag a combination of FLAG_ constants, from the list in
+ * {@link UserInfo#UserInfoFlag}, whose value has changed and the associated
+ * invalidations must therefore be performed.
+ * @hide
+ */
+ public static final void invalidateOnUserInfoFlagChange(@UserInfoFlag int flags) {
+ if ((flags & UserInfo.FLAG_DISABLED) > 0) {
+ invalidateEnabledProfileIds();
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6c03214..7ecfe7f 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1222,7 +1222,7 @@
// Mark the user for removal.
addRemovingUserIdLocked(ui.id);
ui.partial = true;
- ui.flags |= UserInfo.FLAG_DISABLED;
+ addUserInfoFlags(ui, UserInfo.FLAG_DISABLED);
}
/* Prunes out any partially created or partially removed users. */
@@ -1264,7 +1264,7 @@
if (ui.preCreated) {
preCreatedUsers.add(ui);
addRemovingUserIdLocked(ui.id);
- ui.flags |= UserInfo.FLAG_DISABLED;
+ addUserInfoFlags(ui, UserInfo.FLAG_DISABLED);
ui.partial = true;
}
}
@@ -2120,7 +2120,7 @@
info = getUserInfoLU(userId);
if (info != null && !info.isEnabled()) {
wasUserDisabled = true;
- info.flags ^= UserInfo.FLAG_DISABLED;
+ removeUserInfoFlags(info, UserInfo.FLAG_DISABLED);
writeUserLP(getUserDataLU(info.id));
}
}
@@ -2130,6 +2130,36 @@
}
}
+ /**
+ * This method is for monitoring flag changes on users flags and invalidate cache relevant to
+ * the change. The method add flags and invalidateOnUserInfoFlagChange for the flags which
+ * has changed.
+ * @param userInfo of existing user in mUsers list
+ * @param flags to be added to userInfo
+ */
+ private void addUserInfoFlags(UserInfo userInfo, @UserInfoFlag int flags) {
+ int diff = ~userInfo.flags & flags;
+ if (diff > 0) {
+ userInfo.flags |= diff;
+ UserManager.invalidateOnUserInfoFlagChange(diff);
+ }
+ }
+
+ /**
+ * This method is for monitoring flag changes on users flags and invalidate cache relevant to
+ * the change. The method remove flags and invalidateOnUserInfoFlagChange for the flags which
+ * has changed.
+ * @param userInfo of existing user in mUsers list
+ * @param flags to be removed from userInfo
+ */
+ private void removeUserInfoFlags(UserInfo userInfo, @UserInfoFlag int flags) {
+ int diff = userInfo.flags & flags;
+ if (diff > 0) {
+ userInfo.flags ^= diff;
+ UserManager.invalidateOnUserInfoFlagChange(diff);
+ }
+ }
+
@Override
public void setUserAdmin(@UserIdInt int userId) {
checkManageUserAndAcrossUsersFullPermission("set user admin");
@@ -6245,7 +6275,7 @@
userData.info.guestToRemove = true;
// Mark it as disabled, so that it isn't returned any more when
// profiles are queried.
- userData.info.flags |= UserInfo.FLAG_DISABLED;
+ addUserInfoFlags(userData.info, UserInfo.FLAG_DISABLED);
writeUserLP(userData);
}
} finally {
@@ -6390,7 +6420,7 @@
}
// Mark it as disabled, so that it isn't returned any more when
// profiles are queried.
- userData.info.flags |= UserInfo.FLAG_DISABLED;
+ addUserInfoFlags(userData.info, UserInfo.FLAG_DISABLED);
writeUserLP(userData);
}
@@ -7789,7 +7819,7 @@
if (userInfo != null && userInfo.isEphemeral()) {
// Do not allow switching back to the ephemeral user again as the user is going
// to be deleted.
- userInfo.flags |= UserInfo.FLAG_DISABLED;
+ addUserInfoFlags(userInfo, UserInfo.FLAG_DISABLED);
if (userInfo.isGuest()) {
// Indicate that the guest will be deleted after it stops.
userInfo.guestToRemove = true;