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

Commit 964d2f3b authored by Anna Bauza's avatar Anna Bauza Committed by Android (Google) Code Review
Browse files

Merge "Cache user serial numbers" into main

parents 8919ed06 15377a2b
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -6367,6 +6367,33 @@ public class UserManager {
                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
     * when deleting and creating users, but serial numbers are not reused until the device is wiped.
@@ -6376,6 +6403,14 @@ public class UserManager {
     */
    @UnsupportedAppUsage
    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 {
            return mService.getUserSerialNumber(userId);
        } catch (RemoteException re) {
+2 −0
Original line number Diff line number Diff line
@@ -5975,6 +5975,7 @@ public class UserManagerService extends IUserManager.Stub {
    @VisibleForTesting
    void removeUserInfo(@UserIdInt int userId) {
        synchronized (mUsersLock) {
            UserManager.invalidateUserSerialNumberCache();
            mUsers.remove(userId);
        }
    }
@@ -6400,6 +6401,7 @@ public class UserManagerService extends IUserManager.Stub {

        // Remove this user from the list
        synchronized (mUsersLock) {
            UserManager.invalidateUserSerialNumberCache();
            mUsers.remove(userId);
            mIsUserManaged.delete(userId);
        }
+33 −0
Original line number Diff line number Diff line
@@ -1422,6 +1422,39 @@ public final class UserManagerTest {
                (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
    @Test
    public void testMaxUsers() {