Merge "Binder cache for isUserUnlocked()."

This commit is contained in:
Lee Shombert
2020-02-11 15:13:38 +00:00
committed by Android (Google) Code Review
3 changed files with 107 additions and 11 deletions

View File

@@ -34,6 +34,7 @@ import android.annotation.WorkerThread;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.PropertyInvalidatedCache;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -2150,16 +2151,38 @@ public class UserManager {
return isUserUnlocked(user.getIdentifier());
}
private static final String CACHE_KEY_IS_USER_UNLOCKED_PROPERTY =
"cache_key.is_user_unlocked";
private final PropertyInvalidatedCache<Integer, Boolean> mIsUserUnlockedCache =
new PropertyInvalidatedCache<Integer, Boolean>(
32, CACHE_KEY_IS_USER_UNLOCKED_PROPERTY) {
@Override
protected Boolean recompute(Integer query) {
try {
return mService.isUserUnlocked(query);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
};
/** {@hide} */
@UnsupportedAppUsage
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
public boolean isUserUnlocked(@UserIdInt int userId) {
try {
return mService.isUserUnlocked(userId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
return mIsUserUnlockedCache.query(userId);
}
/** {@hide} */
public void disableIsUserUnlockedCache() {
mIsUserUnlockedCache.disableLocal();
}
/** {@hide} */
public static final void invalidateIsUserUnlockedCache() {
PropertyInvalidatedCache.invalidateCache(CACHE_KEY_IS_USER_UNLOCKED_PROPERTY);
}
/**

View File

@@ -342,9 +342,43 @@ class StorageManagerService extends IStorageManager.Stub
*/
private final Object mPackagesLock = new Object();
/**
* mLocalUnlockedUsers affects the return value of isUserUnlocked. If
* any value in the array changes, then the binder cache for
* isUserUnlocked must be invalidated. When adding mutating methods to
* WatchedLockedUsers, be sure to invalidate the cache in the new
* methods.
*/
private class WatchedLockedUsers {
private int[] users = EmptyArray.INT;
public WatchedLockedUsers() {
}
public void append(int userId) {
users = ArrayUtils.appendInt(users, userId);
invalidateIsUserUnlockedCache();
}
public void remove(int userId) {
users = ArrayUtils.removeInt(users, userId);
invalidateIsUserUnlockedCache();
}
public boolean contains(int userId) {
return ArrayUtils.contains(users, userId);
}
public int[] all() {
return users;
}
@Override
public String toString() {
return Arrays.toString(users);
}
private void invalidateIsUserUnlockedCache() {
UserManager.invalidateIsUserUnlockedCache();
}
}
/** Set of users that we know are unlocked. */
@GuardedBy("mLock")
private int[] mLocalUnlockedUsers = EmptyArray.INT;
private WatchedLockedUsers mLocalUnlockedUsers = new WatchedLockedUsers();
/** Set of users that system knows are unlocked. */
@GuardedBy("mLock")
private int[] mSystemUnlockedUsers = EmptyArray.INT;
@@ -3042,7 +3076,7 @@ class StorageManagerService extends IStorageManager.Stub
}
synchronized (mLock) {
mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
mLocalUnlockedUsers.append(userId);
}
}
@@ -3058,14 +3092,14 @@ class StorageManagerService extends IStorageManager.Stub
}
synchronized (mLock) {
mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
mLocalUnlockedUsers.remove(userId);
}
}
@Override
public boolean isUserKeyUnlocked(int userId) {
synchronized (mLock) {
return ArrayUtils.contains(mLocalUnlockedUsers, userId);
return mLocalUnlockedUsers.contains(userId);
}
}
@@ -4177,7 +4211,7 @@ class StorageManagerService extends IStorageManager.Stub
}
pw.println();
pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
pw.println("Local unlocked users: " + mLocalUnlockedUsers);
pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
final ContentResolver cr = mContext.getContentResolver();

View File

@@ -462,8 +462,42 @@ public class UserManagerService extends IUserManager.Stub {
@GuardedBy("mUsersLock")
private boolean mForceEphemeralUsers;
/**
* The member mUserStates affects the return value of isUserUnlocked.
* If any value in mUserStates changes, then the binder cache for
* isUserUnlocked must be invalidated. When adding mutating methods to
* WatchedUserStates, be sure to invalidate the cache in the new
* methods.
*/
private class WatchedUserStates {
final SparseIntArray states;
public WatchedUserStates() {
states = new SparseIntArray();
}
public int get(int userId) {
return states.get(userId);
}
public int get(int userId, int fallback) {
return states.indexOfKey(userId) >= 0 ? states.get(userId) : fallback;
}
public void put(int userId, int state) {
states.put(userId, state);
invalidateIsUserUnlockedCache();
}
public void delete(int userId) {
states.delete(userId);
invalidateIsUserUnlockedCache();
}
@Override
public String toString() {
return states.toString();
}
private void invalidateIsUserUnlockedCache() {
UserManager.invalidateIsUserUnlockedCache();
}
}
@GuardedBy("mUserStates")
private final SparseIntArray mUserStates = new SparseIntArray();
private final WatchedUserStates mUserStates = new WatchedUserStates();
private static UserManagerService sInstance;
@@ -4801,6 +4835,11 @@ public class UserManagerService extends IUserManager.Stub {
|| (state == UserState.STATE_RUNNING_UNLOCKED);
}
/**
* The return values of this method are cached in clients. If the
* logic in this function changes then the cache invalidation code
* may need to be revisited.
*/
@Override
public boolean isUserUnlocked(@UserIdInt int userId) {
int state;