Merge "Binder cache for isUserUnlocked()."
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user