Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 56799e09 authored by Varun Shah's avatar Varun Shah
Browse files

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
parent 1e2e150c
Loading
Loading
Loading
Loading
+40 −5
Original line number Diff line number Diff line
@@ -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;
@@ -237,6 +238,44 @@ public class ActivityManager {
    private static final RateLimitingCache<List<ProcessErrorStateInfo>> mErrorProcessesCache =
            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 */
+10 −0
Original line number Diff line number Diff line
@@ -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
     }
}
+9 −0
Original line number Diff line number Diff line
@@ -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;
    }

+4 −0
Original line number Diff line number Diff line
@@ -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());
+4 −0
Original line number Diff line number Diff line
@@ -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);