Fix high volume of binder calls in ContentProvider.
ContentProvider.getUserIdFromAuthority can return USER_NULL when it can't parse auth as int, which can cause high volume of binder calls. This CL fixes this issue by avoiding calling into system server for invalid user ids.
This CL also fixes a bug in UserManager.getUserProperties where it can throw an exception when the user id is not supported. This CL fixes this issue by throwing an IllegalArgumentException instead.
This CL is a part of the effort to reduce the number of binder calls in the system server.
Bug: 350416200
Change-Id: Ied72302db0c141fe9ff398009331ce44a0fad2e7
Test: atest com.android.server.pm.UserManagerTest
Flag: android.multiuser.cache_user_serial_number
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 87fb843..e0553c8 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -2774,6 +2774,10 @@
+ " provider from user:" + mContext.getUserId());
}
if (userId != UserHandle.USER_CURRENT
+ // getUserIdFromAuthority can return USER_NULL when can't cast the userId to
+ // an int, which can cause high volume of binder calls.
+ && (!android.multiuser.Flags.fixGetUserPropertyCache()
+ || userId != UserHandle.USER_NULL)
&& userId != mContext.getUserId()
// Since userId specified in content uri, the provider userId would be
// determined from it.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f30a9f5..984bf65 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3927,7 +3927,12 @@
android.Manifest.permission.QUERY_USERS,
android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
public @NonNull UserProperties getUserProperties(@NonNull UserHandle userHandle) {
- return mUserPropertiesCache.query(userHandle.getIdentifier());
+ final int userId = userHandle.getIdentifier();
+ // Avoid calling into system server for invalid user ids.
+ if (android.multiuser.Flags.fixGetUserPropertyCache() && userId < 0) {
+ throw new IllegalArgumentException("Cannot access properties for user " + userId);
+ }
+ return mUserPropertiesCache.query(userId);
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 02d3b59..9003ab6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -1060,6 +1060,23 @@
assertThrows(SecurityException.class, userProps::getAlwaysVisible);
}
+ /**
+ * Test that UserManager.getUserProperties throws the IllegalArgumentException for unsupported
+ * arguments such as UserHandle.NULL, UserHandle.CURRENT or UserHandle.ALL.
+ **/
+ @MediumTest
+ @Test
+ public void testThrowUserPropertiesForUnsupportedUserHandles() throws Exception {
+ assertThrows(IllegalArgumentException.class, () ->
+ mUserManager.getUserProperties(UserHandle.of(UserHandle.USER_NULL)));
+ assertThrows(IllegalArgumentException.class, () ->
+ mUserManager.getUserProperties(UserHandle.CURRENT));
+ assertThrows(IllegalArgumentException.class, () ->
+ mUserManager.getUserProperties(UserHandle.CURRENT_OR_SELF));
+ assertThrows(IllegalArgumentException.class, () ->
+ mUserManager.getUserProperties(UserHandle.ALL));
+ }
+
// Make sure only max managed profiles can be created
@MediumTest
@Test