diff options
| author | 2024-08-29 22:19:46 +0000 | |
|---|---|---|
| committer | 2024-09-04 18:49:53 +0000 | |
| commit | 56799e096df5d1265882505d7d7ca89c6df502bd (patch) | |
| tree | d5e0d167d558f1ccc1e30ca30195a85d0f0dd2e5 | |
| parent | 1e2e150cb1f3562e969fecdb4cf20188bfef79ed (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
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); |