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

Commit 15377a2b authored by Anna Bauza's avatar Anna Bauza
Browse files

Cache user serial numbers

This CL adds a cache for user serial numbers in UserManager. This is done to improve performance, as the UserManagerService can be slow to respond to requests for user serial numbers. The cache is invalidated when a user is removed, so that the cache always contains the most up-to-date information.

Flag: android.multiuser.cache_user_serial_number
Bug: 340018451
Test: atest com.android.server.pm.UserManagerTest
Change-Id: I1ac96c5777b617803a731109005f75fdb554db98
parent b2ea8ff7
Loading
Loading
Loading
Loading
+35 −0
Original line number Original line Diff line number Diff line
@@ -6367,6 +6367,33 @@ public class UserManager {
                Settings.Global.DEVICE_DEMO_MODE, 0) > 0;
                Settings.Global.DEVICE_DEMO_MODE, 0) > 0;
    }
    }


    private static final String CACHE_KEY_USER_SERIAL_NUMBER_PROPERTY =
        PropertyInvalidatedCache.createPropertyName(
            PropertyInvalidatedCache.MODULE_SYSTEM, "user_serial_number");

    private final PropertyInvalidatedCache<Integer, Integer> mUserSerialNumberCache =
            new PropertyInvalidatedCache<Integer, Integer>(
                32, CACHE_KEY_USER_SERIAL_NUMBER_PROPERTY) {
                @Override
                public Integer recompute(Integer query) {
                    try {
                        return mService.getUserSerialNumber(query);
                    } catch (RemoteException re) {
                        throw re.rethrowFromSystemServer();
                    }
                }
                @Override
                public boolean bypass(Integer query) {
                    return query <= 0;
                }
            };


    /** @hide */
    public static final void invalidateUserSerialNumberCache() {
        PropertyInvalidatedCache.invalidateCache(CACHE_KEY_USER_SERIAL_NUMBER_PROPERTY);
    }

    /**
    /**
     * Returns a serial number on this device for a given userId. User handles can be recycled
     * Returns a serial number on this device for a given userId. User handles can be recycled
     * when deleting and creating users, but serial numbers are not reused until the device is wiped.
     * when deleting and creating users, but serial numbers are not reused until the device is wiped.
@@ -6376,6 +6403,14 @@ public class UserManager {
     */
     */
    @UnsupportedAppUsage
    @UnsupportedAppUsage
    public int getUserSerialNumber(@UserIdInt int userId) {
    public int getUserSerialNumber(@UserIdInt int userId) {
        if (android.multiuser.Flags.cacheUserSerialNumber()) {
            // System user serial number is always 0, and it always exists.
            // There is no need to call binder for that.
            if (userId == UserHandle.USER_SYSTEM) {
               return UserHandle.USER_SERIAL_SYSTEM;
            }
            return mUserSerialNumberCache.query(userId);
        }
        try {
        try {
            return mService.getUserSerialNumber(userId);
            return mService.getUserSerialNumber(userId);
        } catch (RemoteException re) {
        } catch (RemoteException re) {
+2 −0
Original line number Original line Diff line number Diff line
@@ -5975,6 +5975,7 @@ public class UserManagerService extends IUserManager.Stub {
    @VisibleForTesting
    @VisibleForTesting
    void removeUserInfo(@UserIdInt int userId) {
    void removeUserInfo(@UserIdInt int userId) {
        synchronized (mUsersLock) {
        synchronized (mUsersLock) {
            UserManager.invalidateUserSerialNumberCache();
            mUsers.remove(userId);
            mUsers.remove(userId);
        }
        }
    }
    }
@@ -6400,6 +6401,7 @@ public class UserManagerService extends IUserManager.Stub {


        // Remove this user from the list
        // Remove this user from the list
        synchronized (mUsersLock) {
        synchronized (mUsersLock) {
            UserManager.invalidateUserSerialNumberCache();
            mUsers.remove(userId);
            mUsers.remove(userId);
            mIsUserManaged.delete(userId);
            mIsUserManaged.delete(userId);
        }
        }
+33 −0
Original line number Original line Diff line number Diff line
@@ -1422,6 +1422,39 @@ public final class UserManagerTest {
                (long) user1.serialNumber, (long) user2.serialNumber);
                (long) user1.serialNumber, (long) user2.serialNumber);
    }
    }


    @MediumTest
    @Test
    public void testSerialNumberAfterUserRemoval() {
        final UserInfo user = mUserManager.createUser("Test User", 0);
        assertThat(user).isNotNull();

        final int userId = user.id;
        assertThat(mUserManager.getUserSerialNumber(userId))
            .isEqualTo(user.serialNumber);
        mUsersToRemove.add(userId);
        removeUser(userId);
        int serialNumber = mUserManager.getUserSerialNumber(userId);
        int timeout = REMOVE_USER_TIMEOUT_SECONDS * 5; // called every 200ms

        // Wait for the user to be removed from memory
        while(serialNumber > 0 && timeout > 0){
          sleep(200);
          timeout--;
          serialNumber = mUserManager.getUserSerialNumber(userId);
        }
        assertThat(serialNumber).isEqualTo(-1);
    }


    private void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    @MediumTest
    @MediumTest
    @Test
    @Test
    public void testMaxUsers() {
    public void testMaxUsers() {