summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Varun Shah <varunshah@google.com> 2024-08-29 22:19:46 +0000
committer Varun Shah <varunshah@google.com> 2024-09-04 18:49:53 +0000
commit56799e096df5d1265882505d7d7ca89c6df502bd (patch)
treed5e0d167d558f1ccc1e30ca30195a85d0f0dd2e5
parent1e2e150cb1f3562e969fecdb4cf20188bfef79ed (diff)
Add caching to AM.getCurrentUserId().
The current foreground user doesn't change outside of a user switch, which is a rare event on most user devices. Add a IpcDataCache to AM.getCurrentUserId() in order to avoid unncessary binder spam. Flag: backstage_power/android.app.cache_get_current_user_id Bug: 361853873 Test: atest UserControllerTest Test: atest UserManagerTest Test: atest ActivityManagerTest Test: manually check logs for cache hits/misses Change-Id: I94540ad4c76bcc62944ad8e19f0e9d6c2154b010
-rw-r--r--core/java/android/app/ActivityManager.java45
-rw-r--r--core/java/android/app/activity_manager.aconfig10
-rw-r--r--services/core/java/com/android/server/am/UserController.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UserControllerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java4
5 files changed, 67 insertions, 5 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 68063c4a1a50..b83be6b86d04 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -66,6 +66,7 @@ import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IpcDataCache;
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
@@ -238,6 +239,44 @@ public class ActivityManager {
new RateLimitingCache<>(10, 2);
/**
+ * Query handler for mGetCurrentUserIdCache - returns a cached value of the current foreground
+ * user id if the backstage_power/android.app.cache_get_current_user_id flag is enabled.
+ */
+ private static final IpcDataCache.QueryHandler<Void, Integer> mGetCurrentUserIdQuery =
+ new IpcDataCache.QueryHandler<>() {
+ @Override
+ public Integer apply(Void query) {
+ try {
+ return getService().getCurrentUserId();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public boolean shouldBypassCache(Void query) {
+ // If the flag to enable the new caching behavior is off, bypass the cache.
+ return !Flags.cacheGetCurrentUserId();
+ }
+ };
+
+ /** A cache which maintains the current foreground user id. */
+ private static final IpcDataCache<Void, Integer> mGetCurrentUserIdCache =
+ new IpcDataCache<>(1, IpcDataCache.MODULE_SYSTEM,
+ /* api= */ "getCurrentUserId", /* cacheName= */ "CurrentUserIdCache",
+ mGetCurrentUserIdQuery);
+
+ /**
+ * The current foreground user has changed - invalidate the cache. Currently only called from
+ * UserController when a user switch occurs.
+ * @hide
+ */
+ public static void invalidateGetCurrentUserIdCache() {
+ IpcDataCache.invalidateCache(
+ IpcDataCache.MODULE_SYSTEM, /* api= */ "getCurrentUserId");
+ }
+
+ /**
* Map of callbacks that have registered for {@link UidFrozenStateChanged} events.
* Will be called when a Uid has become frozen or unfrozen.
*/
@@ -5244,11 +5283,7 @@ public class ActivityManager {
})
@android.ravenwood.annotation.RavenwoodReplace
public static int getCurrentUser() {
- try {
- return getService().getCurrentUserId();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return mGetCurrentUserIdCache.query(null);
}
/** @hide */
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index 32e6e80cc3e9..4c97dbbb4d01 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -104,3 +104,13 @@ flag {
}
}
+flag {
+ namespace: "backstage_power"
+ name: "cache_get_current_user_id"
+ description: "Add caching for getCurrentUserId"
+ is_fixed_read_only: true
+ bug: "361853873"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index bdba6bcf66c0..b186eaacab74 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1978,6 +1978,7 @@ class UserController implements Handler.Callback {
boolean userSwitchUiEnabled;
synchronized (mLock) {
mCurrentUserId = userId;
+ ActivityManager.invalidateGetCurrentUserIdCache();
userSwitchUiEnabled = mUserSwitchUiEnabled;
}
mInjector.updateUserConfiguration();
@@ -2239,6 +2240,7 @@ class UserController implements Handler.Callback {
return true;
}
mTargetUserId = targetUserId;
+ ActivityManager.invalidateGetCurrentUserIdCache();
userSwitchUiEnabled = mUserSwitchUiEnabled;
}
if (userSwitchUiEnabled) {
@@ -2316,6 +2318,7 @@ class UserController implements Handler.Callback {
synchronized (mLock) {
nextUserId = ObjectUtils.getOrElse(mPendingTargetUserIds.poll(), UserHandle.USER_NULL);
mTargetUserId = UserHandle.USER_NULL;
+ ActivityManager.invalidateGetCurrentUserIdCache();
}
if (nextUserId != UserHandle.USER_NULL) {
switchUser(nextUserId);
@@ -3021,6 +3024,9 @@ class UserController implements Handler.Callback {
mInjector.getUserManagerInternal().addUserLifecycleListener(mUserLifecycleListener);
updateProfileRelatedCaches();
mInjector.reportCurWakefulnessUsageEvent();
+
+ // IpcDataCache must be invalidated before it starts caching.
+ ActivityManager.invalidateGetCurrentUserIdCache();
}
// TODO(b/266158156): remove this method if initial system user boot logic is refactored?
@@ -3184,6 +3190,9 @@ class UserController implements Handler.Callback {
@GuardedBy("mLock")
private int getCurrentOrTargetUserIdLU() {
+ // Note: this result is currently cached by ActivityManager.getCurrentUser() - changes to
+ // the logic here may require updating how the cache is invalidated.
+ // See ActivityManager.invalidateGetCurrentUserIdCache() for more details.
return mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
}
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 1db46bf17655..f7733242d491 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -89,6 +89,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IRemoteCallback;
+import android.os.IpcDataCache;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManagerInternal;
@@ -197,6 +198,9 @@ public class UserControllerTest {
@Before
public void setUp() throws Exception {
runWithDexmakerShareClassLoader(() -> {
+ // Disable binder caches in this process.
+ IpcDataCache.disableForTestMode();
+
mInjector = spy(new TestInjector(getInstrumentation().getTargetContext()));
doNothing().when(mInjector).clearAllLockedTasks(anyString());
doNothing().when(mInjector).startHomeActivity(anyInt(), anyString());
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 791215695f57..e652df5cdf1a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -34,6 +34,7 @@ import android.content.pm.UserProperties;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.IpcDataCache;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.os.UserManager;
@@ -100,6 +101,9 @@ public final class UserManagerTest {
@Before
public void setUp() throws Exception {
+ // Disable binder caches in this process.
+ IpcDataCache.disableForTestMode();
+
mOriginalCurrentUserId = ActivityManager.getCurrentUser();
mUserManager = UserManager.get(mContext);
mActivityManager = mContext.getSystemService(ActivityManager.class);