Loading services/core/java/com/android/server/role/RoleManagerService.java +45 −61 Original line number Diff line number Diff line Loading @@ -156,21 +156,16 @@ public class RoleManagerService extends SystemService { @MainThread private void performInitialGrantsIfNecessary(@UserIdInt int userId) { RoleUserState userState; synchronized (mLock) { userState = getUserStateLocked(userId); } userState = getOrCreateUserState(userId); String packagesHash = computeComponentStateHash(userId); String oldPackagesHash; synchronized (mLock) { oldPackagesHash = userState.getPackagesHashLocked(); } String oldPackagesHash = userState.getPackagesHash(); boolean needGrant = !Objects.equals(packagesHash, oldPackagesHash); if (needGrant) { // Some vital packages state has changed since last role grant // Run grants again Slog.i(LOG_TAG, "Granting default permissions..."); CompletableFuture<Void> result = new CompletableFuture<>(); getControllerService(userId).onGrantDefaultRoles( getOrCreateControllerService(userId).onGrantDefaultRoles( new IRoleManagerCallback.Stub() { @Override public void onSuccess() { Loading @@ -183,9 +178,7 @@ public class RoleManagerService extends SystemService { }); try { result.get(5, TimeUnit.SECONDS); synchronized (mLock) { userState.setPackagesHashLocked(packagesHash); } userState.setPackagesHash(packagesHash); } catch (InterruptedException | ExecutionException | TimeoutException e) { Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, e); } Loading Loading @@ -225,20 +218,21 @@ public class RoleManagerService extends SystemService { return PackageUtils.computeSha256Digest(out.toByteArray()); } @GuardedBy("mLock") @NonNull private RoleUserState getUserStateLocked(@UserIdInt int userId) { private RoleUserState getOrCreateUserState(@UserIdInt int userId) { synchronized (mLock) { RoleUserState userState = mUserStates.get(userId); if (userState == null) { userState = RoleUserState.newInstanceLocked(userId); userState = new RoleUserState(userId); mUserStates.put(userId, userState); } return userState; } } @GuardedBy("mLock") @NonNull private RemoteRoleControllerService getControllerService(@UserIdInt int userId) { private RemoteRoleControllerService getOrCreateControllerService(@UserIdInt int userId) { synchronized (mLock) { RemoteRoleControllerService controllerService = mControllerServices.get(userId); if (controllerService == null) { controllerService = new RemoteRoleControllerService(userId, getContext()); Loading @@ -246,14 +240,16 @@ public class RoleManagerService extends SystemService { } return controllerService; } } private void onRemoveUser(@UserIdInt int userId) { RoleUserState userState; synchronized (mLock) { mControllerServices.remove(userId); RoleUserState userState = mUserStates.removeReturnOld(userId); if (userState != null) { userState.destroyLocked(); userState = mUserStates.removeReturnOld(userId); } if (userState != null) { userState.destroy(); } } Loading @@ -264,10 +260,8 @@ public class RoleManagerService extends SystemService { Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); int userId = UserHandle.getUserId(getCallingUid()); synchronized (mLock) { RoleUserState userState = getUserStateLocked(userId); return userState.isRoleAvailableLocked(roleName); } RoleUserState userState = getOrCreateUserState(userId); return userState.isRoleAvailable(roleName); } @Override Loading Loading @@ -307,10 +301,8 @@ public class RoleManagerService extends SystemService { @Nullable private ArraySet<String> getRoleHoldersInternal(@NonNull String roleName, @UserIdInt int userId) { synchronized (mLock) { RoleUserState userState = getUserStateLocked(userId); return userState.getRoleHoldersLocked(roleName); } RoleUserState userState = getOrCreateUserState(userId); return userState.getRoleHolders(roleName); } @Override Loading @@ -327,7 +319,7 @@ public class RoleManagerService extends SystemService { getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "addRoleHolderAsUser"); getControllerService(userId).onAddRoleHolder(roleName, packageName, callback); getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, callback); } @Override Loading @@ -344,7 +336,7 @@ public class RoleManagerService extends SystemService { getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "removeRoleHolderAsUser"); getControllerService(userId).onRemoveRoleHolder(roleName, packageName, getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName, callback); } Loading @@ -361,7 +353,7 @@ public class RoleManagerService extends SystemService { getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "clearRoleHoldersAsUser"); getControllerService(userId).onClearRoleHolders(roleName, callback); getOrCreateControllerService(userId).onClearRoleHolders(roleName, callback); } @Override Loading @@ -372,10 +364,8 @@ public class RoleManagerService extends SystemService { "setRoleNamesFromController"); int userId = UserHandle.getCallingUserId(); synchronized (mLock) { RoleUserState userState = getUserStateLocked(userId); userState.setRoleNamesLocked(roleNames); } RoleUserState userState = getOrCreateUserState(userId); userState.setRoleNames(roleNames); } @Override Loading @@ -388,10 +378,8 @@ public class RoleManagerService extends SystemService { "addRoleHolderFromController"); int userId = UserHandle.getCallingUserId(); synchronized (mLock) { RoleUserState userState = getUserStateLocked(userId); return userState.addRoleHolderLocked(roleName, packageName); } RoleUserState userState = getOrCreateUserState(userId); return userState.addRoleHolder(roleName, packageName); } @Override Loading @@ -404,10 +392,8 @@ public class RoleManagerService extends SystemService { "removeRoleHolderFromController"); int userId = UserHandle.getCallingUserId(); synchronized (mLock) { RoleUserState userState = getUserStateLocked(userId); return userState.removeRoleHolderLocked(roleName, packageName); } RoleUserState userState = getOrCreateUserState(userId); return userState.removeRoleHolder(roleName, packageName); } @CheckResult Loading Loading @@ -440,17 +426,15 @@ public class RoleManagerService extends SystemService { dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, " ")); } synchronized (mLock) { int[] userIds = mUserManagerInternal.getUserIds(); int userIdsLength = userIds.length; for (int i = 0; i < userIdsLength; i++) { int userId = userIds[i]; RoleUserState userState = getUserStateLocked(userId); userState.dumpLocked(dumpOutputStream, "user_states", RoleUserState userState = getOrCreateUserState(userId); userState.dump(dumpOutputStream, "user_states", RoleManagerServiceDumpProto.USER_STATES); } } dumpOutputStream.flush(); } Loading services/core/java/com/android/server/role/RoleUserState.java +171 −138 Original line number Diff line number Diff line Loading @@ -74,69 +74,67 @@ public class RoleUserState { @UserIdInt private final int mUserId; @GuardedBy("RoleManagerService.mLock") @NonNull private final Object mLock = new Object(); @GuardedBy("mLock") private int mVersion = VERSION_UNDEFINED; @GuardedBy("RoleManagerService.mLock") @GuardedBy("mLock") @Nullable private String mPackagesHash; /** * Maps role names to its holders' package names. The values should never be null. */ @GuardedBy("RoleManagerService.mLock") @GuardedBy("mLock") @NonNull private ArrayMap<String, ArraySet<String>> mRoles = new ArrayMap<>(); @GuardedBy("RoleManagerService.mLock") @GuardedBy("mLock") private long mWritePendingSinceMillis; @GuardedBy("RoleManagerService.mLock") @GuardedBy("mLock") private boolean mDestroyed; @NonNull private final Handler mWriteHandler = new Handler(BackgroundThread.getHandler().getLooper()); private RoleUserState(@UserIdInt int userId) { mUserId = userId; readLocked(); } /** * Create a new instance of user state, and read its state from disk if previously persisted. * * @param userId the user id for the new user state * * @return the new user state */ @GuardedBy("RoleManagerService.mLock") public static RoleUserState newInstanceLocked(@UserIdInt int userId) { return new RoleUserState(userId); public RoleUserState(@UserIdInt int userId) { mUserId = userId; readFile(); } /** * Get the version of this user state. */ @GuardedBy("RoleManagerService.mLock") public int getVersionLocked() { public int getVersion() { synchronized (mLock) { throwIfDestroyedLocked(); return mVersion; } } /** * Set the version of this user state. * * @param version the version to set */ @GuardedBy("RoleManagerService.mLock") public void setVersionLocked(int version) { public void setVersion(int version) { synchronized (mLock) { throwIfDestroyedLocked(); if (mVersion == version) { return; } mVersion = version; writeAsyncLocked(); scheduleWriteFileLocked(); } } /** Loading @@ -144,24 +142,27 @@ public class RoleUserState { * * @return the hash representing the state of packages */ @GuardedBy("RoleManagerService.mLock") public String getPackagesHashLocked() { @Nullable public String getPackagesHash() { synchronized (mLock) { return mPackagesHash; } } /** * Set the hash representing the state of packages during the last time initial grants was run. * * @param packagesHash the hash representing the state of packages */ @GuardedBy("RoleManagerService.mLock") public void setPackagesHashLocked(@Nullable String packagesHash) { public void setPackagesHash(@Nullable String packagesHash) { synchronized (mLock) { throwIfDestroyedLocked(); if (Objects.equals(mPackagesHash, packagesHash)) { return; } mPackagesHash = packagesHash; writeAsyncLocked(); scheduleWriteFileLocked(); } } /** Loading @@ -171,11 +172,12 @@ public class RoleUserState { * * @return whether the role is available */ @GuardedBy("RoleManagerService.mLock") public boolean isRoleAvailableLocked(@NonNull String roleName) { public boolean isRoleAvailable(@NonNull String roleName) { synchronized (mLock) { throwIfDestroyedLocked(); return mRoles.containsKey(roleName); } } /** * Get the holders of a role. Loading @@ -184,11 +186,12 @@ public class RoleUserState { * * @return the set of role holders. {@code null} should not be returned and indicates an issue. */ @GuardedBy("RoleManagerService.mLock") @Nullable public ArraySet<String> getRoleHoldersLocked(@NonNull String roleName) { public ArraySet<String> getRoleHolders(@NonNull String roleName) { synchronized (mLock) { throwIfDestroyedLocked(); return mRoles.get(roleName); return new ArraySet<>(mRoles.get(roleName)); } } /** Loading @@ -196,8 +199,8 @@ public class RoleUserState { * * @param roleNames the names of all the available roles */ @GuardedBy("RoleManagerService.mLock") public void setRoleNamesLocked(@NonNull List<String> roleNames) { public void setRoleNames(@NonNull List<String> roleNames) { synchronized (mLock) { throwIfDestroyedLocked(); boolean changed = false; for (int i = mRoles.size() - 1; i >= 0; i--) { Loading @@ -205,7 +208,8 @@ public class RoleUserState { if (!roleNames.contains(roleName)) { ArraySet<String> packageNames = mRoles.valueAt(i); if (!packageNames.isEmpty()) { Slog.e(LOG_TAG, "Holders of a removed role should have been cleaned up, role: " Slog.e(LOG_TAG, "Holders of a removed role should have been cleaned up, role: " + roleName + ", holders: " + packageNames); } mRoles.removeAt(i); Loading @@ -222,7 +226,8 @@ public class RoleUserState { } } if (changed) { writeAsyncLocked(); scheduleWriteFileLocked(); } } } Loading @@ -236,8 +241,8 @@ public class RoleUserState { * indicates an issue. */ @CheckResult @GuardedBy("RoleManagerService.mLock") public boolean addRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) { public boolean addRoleHolder(@NonNull String roleName, @NonNull String packageName) { synchronized (mLock) { throwIfDestroyedLocked(); ArraySet<String> roleHolders = mRoles.get(roleName); if (roleHolders == null) { Loading @@ -247,10 +252,11 @@ public class RoleUserState { } boolean changed = roleHolders.add(packageName); if (changed) { writeAsyncLocked(); scheduleWriteFileLocked(); } return true; } } /** * Remove a holder from a role. Loading @@ -262,8 +268,8 @@ public class RoleUserState { * indicates an issue. */ @CheckResult @GuardedBy("RoleManagerService.mLock") public boolean removeRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) { public boolean removeRoleHolder(@NonNull String roleName, @NonNull String packageName) { synchronized (mLock) { throwIfDestroyedLocked(); ArraySet<String> roleHolders = mRoles.get(roleName); if (roleHolders == null) { Loading @@ -273,27 +279,19 @@ public class RoleUserState { } boolean changed = roleHolders.remove(packageName); if (changed) { writeAsyncLocked(); scheduleWriteFileLocked(); } return true; } } /** * Schedule writing the state to file. */ @GuardedBy("RoleManagerService.mLock") private void writeAsyncLocked() { @GuardedBy("mLock") private void scheduleWriteFileLocked() { throwIfDestroyedLocked(); ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>(); for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) { String roleName = mRoles.keyAt(i); ArraySet<String> roleHolders = mRoles.valueAt(i); roleHolders = new ArraySet<>(roleHolders); roles.put(roleName, roleHolders); } long currentTimeMillis = System.currentTimeMillis(); long writeDelayMillis; if (!mWriteHandler.hasMessagesOrCallbacks()) { Loading @@ -311,14 +309,26 @@ public class RoleUserState { } } mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeSync, this, mVersion, mPackagesHash, roles), writeDelayMillis); mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeFile, this), writeDelayMillis); Slog.i(LOG_TAG, "Scheduled writing roles.xml"); } @WorkerThread private void writeSync(int version, @Nullable String packagesHash, @NonNull ArrayMap<String, ArraySet<String>> roles) { private void writeFile() { int version; String packagesHash; ArrayMap<String, ArraySet<String>> roles; synchronized (mLock) { if (mDestroyed) { return; } version = mVersion; packagesHash = mPackagesHash; roles = snapshotRolesLocked(); } AtomicFile atomicFile = new AtomicFile(getFile(mUserId), "roles-" + mUserId); FileOutputStream out = null; try { Loading Loading @@ -385,8 +395,8 @@ public class RoleUserState { /** * Read the state from file. */ @GuardedBy("RoleManagerService.mLock") private void readLocked() { private void readFile() { synchronized (mLock) { File file = getFile(mUserId); try (FileInputStream in = new AtomicFile(file).openRead()) { XmlPullParser parser = Xml.newPullParser(); Loading @@ -399,6 +409,7 @@ public class RoleUserState { throw new IllegalStateException("Failed to parse roles.xml: " + file, e); } } } private void parseXmlLocked(@NonNull XmlPullParser parser) throws IOException, XmlPullParserException { Loading Loading @@ -470,20 +481,28 @@ public class RoleUserState { * * @param dumpOutputStream the output stream to dump to */ @GuardedBy("RoleManagerService.mLock") public void dumpLocked(@NonNull DualDumpOutputStream dumpOutputStream, @NonNull String fieldName, long fieldId) { public void dump(@NonNull DualDumpOutputStream dumpOutputStream, @NonNull String fieldName, long fieldId) { int version; String packagesHash; ArrayMap<String, ArraySet<String>> roles; synchronized (mLock) { throwIfDestroyedLocked(); version = mVersion; packagesHash = mPackagesHash; roles = snapshotRolesLocked(); } long fieldToken = dumpOutputStream.start(fieldName, fieldId); dumpOutputStream.write("user_id", RoleUserStateProto.USER_ID, mUserId); dumpOutputStream.write("version", RoleUserStateProto.VERSION, mVersion); dumpOutputStream.write("packages_hash", RoleUserStateProto.PACKAGES_HASH, mPackagesHash); dumpOutputStream.write("version", RoleUserStateProto.VERSION, version); dumpOutputStream.write("packages_hash", RoleUserStateProto.PACKAGES_HASH, packagesHash); int rolesSize = mRoles.size(); int rolesSize = roles.size(); for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) { String roleName = mRoles.keyAt(rolesIndex); ArraySet<String> roleHolders = mRoles.valueAt(rolesIndex); String roleName = roles.keyAt(rolesIndex); ArraySet<String> roleHolders = roles.valueAt(rolesIndex); long rolesToken = dumpOutputStream.start("roles", RoleUserStateProto.ROLES); dumpOutputStream.write("name", RoleProto.NAME, roleName); Loading @@ -501,19 +520,33 @@ public class RoleUserState { dumpOutputStream.end(fieldToken); } @GuardedBy("mLock") private ArrayMap<String, ArraySet<String>> snapshotRolesLocked() { ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>(); for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) { String roleName = mRoles.keyAt(i); ArraySet<String> roleHolders = mRoles.valueAt(i); roleHolders = new ArraySet<>(roleHolders); roles.put(roleName, roleHolders); } return roles; } /** * Destroy this state and delete the corresponding file. Any pending writes to the file will be * cancelled and any future interaction with this state will throw an exception. */ @GuardedBy("RoleManagerService.mLock") public void destroyLocked() { public void destroy() { synchronized (mLock) { throwIfDestroyedLocked(); mWriteHandler.removeCallbacksAndMessages(null); getFile(mUserId).delete(); mDestroyed = true; } } @GuardedBy("RoleManagerService.mLock") @GuardedBy("mLock") private void throwIfDestroyedLocked() { if (mDestroyed) { throw new IllegalStateException("This RoleUserState has already been destroyed"); Loading Loading
services/core/java/com/android/server/role/RoleManagerService.java +45 −61 Original line number Diff line number Diff line Loading @@ -156,21 +156,16 @@ public class RoleManagerService extends SystemService { @MainThread private void performInitialGrantsIfNecessary(@UserIdInt int userId) { RoleUserState userState; synchronized (mLock) { userState = getUserStateLocked(userId); } userState = getOrCreateUserState(userId); String packagesHash = computeComponentStateHash(userId); String oldPackagesHash; synchronized (mLock) { oldPackagesHash = userState.getPackagesHashLocked(); } String oldPackagesHash = userState.getPackagesHash(); boolean needGrant = !Objects.equals(packagesHash, oldPackagesHash); if (needGrant) { // Some vital packages state has changed since last role grant // Run grants again Slog.i(LOG_TAG, "Granting default permissions..."); CompletableFuture<Void> result = new CompletableFuture<>(); getControllerService(userId).onGrantDefaultRoles( getOrCreateControllerService(userId).onGrantDefaultRoles( new IRoleManagerCallback.Stub() { @Override public void onSuccess() { Loading @@ -183,9 +178,7 @@ public class RoleManagerService extends SystemService { }); try { result.get(5, TimeUnit.SECONDS); synchronized (mLock) { userState.setPackagesHashLocked(packagesHash); } userState.setPackagesHash(packagesHash); } catch (InterruptedException | ExecutionException | TimeoutException e) { Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, e); } Loading Loading @@ -225,20 +218,21 @@ public class RoleManagerService extends SystemService { return PackageUtils.computeSha256Digest(out.toByteArray()); } @GuardedBy("mLock") @NonNull private RoleUserState getUserStateLocked(@UserIdInt int userId) { private RoleUserState getOrCreateUserState(@UserIdInt int userId) { synchronized (mLock) { RoleUserState userState = mUserStates.get(userId); if (userState == null) { userState = RoleUserState.newInstanceLocked(userId); userState = new RoleUserState(userId); mUserStates.put(userId, userState); } return userState; } } @GuardedBy("mLock") @NonNull private RemoteRoleControllerService getControllerService(@UserIdInt int userId) { private RemoteRoleControllerService getOrCreateControllerService(@UserIdInt int userId) { synchronized (mLock) { RemoteRoleControllerService controllerService = mControllerServices.get(userId); if (controllerService == null) { controllerService = new RemoteRoleControllerService(userId, getContext()); Loading @@ -246,14 +240,16 @@ public class RoleManagerService extends SystemService { } return controllerService; } } private void onRemoveUser(@UserIdInt int userId) { RoleUserState userState; synchronized (mLock) { mControllerServices.remove(userId); RoleUserState userState = mUserStates.removeReturnOld(userId); if (userState != null) { userState.destroyLocked(); userState = mUserStates.removeReturnOld(userId); } if (userState != null) { userState.destroy(); } } Loading @@ -264,10 +260,8 @@ public class RoleManagerService extends SystemService { Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); int userId = UserHandle.getUserId(getCallingUid()); synchronized (mLock) { RoleUserState userState = getUserStateLocked(userId); return userState.isRoleAvailableLocked(roleName); } RoleUserState userState = getOrCreateUserState(userId); return userState.isRoleAvailable(roleName); } @Override Loading Loading @@ -307,10 +301,8 @@ public class RoleManagerService extends SystemService { @Nullable private ArraySet<String> getRoleHoldersInternal(@NonNull String roleName, @UserIdInt int userId) { synchronized (mLock) { RoleUserState userState = getUserStateLocked(userId); return userState.getRoleHoldersLocked(roleName); } RoleUserState userState = getOrCreateUserState(userId); return userState.getRoleHolders(roleName); } @Override Loading @@ -327,7 +319,7 @@ public class RoleManagerService extends SystemService { getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "addRoleHolderAsUser"); getControllerService(userId).onAddRoleHolder(roleName, packageName, callback); getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, callback); } @Override Loading @@ -344,7 +336,7 @@ public class RoleManagerService extends SystemService { getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "removeRoleHolderAsUser"); getControllerService(userId).onRemoveRoleHolder(roleName, packageName, getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName, callback); } Loading @@ -361,7 +353,7 @@ public class RoleManagerService extends SystemService { getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "clearRoleHoldersAsUser"); getControllerService(userId).onClearRoleHolders(roleName, callback); getOrCreateControllerService(userId).onClearRoleHolders(roleName, callback); } @Override Loading @@ -372,10 +364,8 @@ public class RoleManagerService extends SystemService { "setRoleNamesFromController"); int userId = UserHandle.getCallingUserId(); synchronized (mLock) { RoleUserState userState = getUserStateLocked(userId); userState.setRoleNamesLocked(roleNames); } RoleUserState userState = getOrCreateUserState(userId); userState.setRoleNames(roleNames); } @Override Loading @@ -388,10 +378,8 @@ public class RoleManagerService extends SystemService { "addRoleHolderFromController"); int userId = UserHandle.getCallingUserId(); synchronized (mLock) { RoleUserState userState = getUserStateLocked(userId); return userState.addRoleHolderLocked(roleName, packageName); } RoleUserState userState = getOrCreateUserState(userId); return userState.addRoleHolder(roleName, packageName); } @Override Loading @@ -404,10 +392,8 @@ public class RoleManagerService extends SystemService { "removeRoleHolderFromController"); int userId = UserHandle.getCallingUserId(); synchronized (mLock) { RoleUserState userState = getUserStateLocked(userId); return userState.removeRoleHolderLocked(roleName, packageName); } RoleUserState userState = getOrCreateUserState(userId); return userState.removeRoleHolder(roleName, packageName); } @CheckResult Loading Loading @@ -440,17 +426,15 @@ public class RoleManagerService extends SystemService { dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, " ")); } synchronized (mLock) { int[] userIds = mUserManagerInternal.getUserIds(); int userIdsLength = userIds.length; for (int i = 0; i < userIdsLength; i++) { int userId = userIds[i]; RoleUserState userState = getUserStateLocked(userId); userState.dumpLocked(dumpOutputStream, "user_states", RoleUserState userState = getOrCreateUserState(userId); userState.dump(dumpOutputStream, "user_states", RoleManagerServiceDumpProto.USER_STATES); } } dumpOutputStream.flush(); } Loading
services/core/java/com/android/server/role/RoleUserState.java +171 −138 Original line number Diff line number Diff line Loading @@ -74,69 +74,67 @@ public class RoleUserState { @UserIdInt private final int mUserId; @GuardedBy("RoleManagerService.mLock") @NonNull private final Object mLock = new Object(); @GuardedBy("mLock") private int mVersion = VERSION_UNDEFINED; @GuardedBy("RoleManagerService.mLock") @GuardedBy("mLock") @Nullable private String mPackagesHash; /** * Maps role names to its holders' package names. The values should never be null. */ @GuardedBy("RoleManagerService.mLock") @GuardedBy("mLock") @NonNull private ArrayMap<String, ArraySet<String>> mRoles = new ArrayMap<>(); @GuardedBy("RoleManagerService.mLock") @GuardedBy("mLock") private long mWritePendingSinceMillis; @GuardedBy("RoleManagerService.mLock") @GuardedBy("mLock") private boolean mDestroyed; @NonNull private final Handler mWriteHandler = new Handler(BackgroundThread.getHandler().getLooper()); private RoleUserState(@UserIdInt int userId) { mUserId = userId; readLocked(); } /** * Create a new instance of user state, and read its state from disk if previously persisted. * * @param userId the user id for the new user state * * @return the new user state */ @GuardedBy("RoleManagerService.mLock") public static RoleUserState newInstanceLocked(@UserIdInt int userId) { return new RoleUserState(userId); public RoleUserState(@UserIdInt int userId) { mUserId = userId; readFile(); } /** * Get the version of this user state. */ @GuardedBy("RoleManagerService.mLock") public int getVersionLocked() { public int getVersion() { synchronized (mLock) { throwIfDestroyedLocked(); return mVersion; } } /** * Set the version of this user state. * * @param version the version to set */ @GuardedBy("RoleManagerService.mLock") public void setVersionLocked(int version) { public void setVersion(int version) { synchronized (mLock) { throwIfDestroyedLocked(); if (mVersion == version) { return; } mVersion = version; writeAsyncLocked(); scheduleWriteFileLocked(); } } /** Loading @@ -144,24 +142,27 @@ public class RoleUserState { * * @return the hash representing the state of packages */ @GuardedBy("RoleManagerService.mLock") public String getPackagesHashLocked() { @Nullable public String getPackagesHash() { synchronized (mLock) { return mPackagesHash; } } /** * Set the hash representing the state of packages during the last time initial grants was run. * * @param packagesHash the hash representing the state of packages */ @GuardedBy("RoleManagerService.mLock") public void setPackagesHashLocked(@Nullable String packagesHash) { public void setPackagesHash(@Nullable String packagesHash) { synchronized (mLock) { throwIfDestroyedLocked(); if (Objects.equals(mPackagesHash, packagesHash)) { return; } mPackagesHash = packagesHash; writeAsyncLocked(); scheduleWriteFileLocked(); } } /** Loading @@ -171,11 +172,12 @@ public class RoleUserState { * * @return whether the role is available */ @GuardedBy("RoleManagerService.mLock") public boolean isRoleAvailableLocked(@NonNull String roleName) { public boolean isRoleAvailable(@NonNull String roleName) { synchronized (mLock) { throwIfDestroyedLocked(); return mRoles.containsKey(roleName); } } /** * Get the holders of a role. Loading @@ -184,11 +186,12 @@ public class RoleUserState { * * @return the set of role holders. {@code null} should not be returned and indicates an issue. */ @GuardedBy("RoleManagerService.mLock") @Nullable public ArraySet<String> getRoleHoldersLocked(@NonNull String roleName) { public ArraySet<String> getRoleHolders(@NonNull String roleName) { synchronized (mLock) { throwIfDestroyedLocked(); return mRoles.get(roleName); return new ArraySet<>(mRoles.get(roleName)); } } /** Loading @@ -196,8 +199,8 @@ public class RoleUserState { * * @param roleNames the names of all the available roles */ @GuardedBy("RoleManagerService.mLock") public void setRoleNamesLocked(@NonNull List<String> roleNames) { public void setRoleNames(@NonNull List<String> roleNames) { synchronized (mLock) { throwIfDestroyedLocked(); boolean changed = false; for (int i = mRoles.size() - 1; i >= 0; i--) { Loading @@ -205,7 +208,8 @@ public class RoleUserState { if (!roleNames.contains(roleName)) { ArraySet<String> packageNames = mRoles.valueAt(i); if (!packageNames.isEmpty()) { Slog.e(LOG_TAG, "Holders of a removed role should have been cleaned up, role: " Slog.e(LOG_TAG, "Holders of a removed role should have been cleaned up, role: " + roleName + ", holders: " + packageNames); } mRoles.removeAt(i); Loading @@ -222,7 +226,8 @@ public class RoleUserState { } } if (changed) { writeAsyncLocked(); scheduleWriteFileLocked(); } } } Loading @@ -236,8 +241,8 @@ public class RoleUserState { * indicates an issue. */ @CheckResult @GuardedBy("RoleManagerService.mLock") public boolean addRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) { public boolean addRoleHolder(@NonNull String roleName, @NonNull String packageName) { synchronized (mLock) { throwIfDestroyedLocked(); ArraySet<String> roleHolders = mRoles.get(roleName); if (roleHolders == null) { Loading @@ -247,10 +252,11 @@ public class RoleUserState { } boolean changed = roleHolders.add(packageName); if (changed) { writeAsyncLocked(); scheduleWriteFileLocked(); } return true; } } /** * Remove a holder from a role. Loading @@ -262,8 +268,8 @@ public class RoleUserState { * indicates an issue. */ @CheckResult @GuardedBy("RoleManagerService.mLock") public boolean removeRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) { public boolean removeRoleHolder(@NonNull String roleName, @NonNull String packageName) { synchronized (mLock) { throwIfDestroyedLocked(); ArraySet<String> roleHolders = mRoles.get(roleName); if (roleHolders == null) { Loading @@ -273,27 +279,19 @@ public class RoleUserState { } boolean changed = roleHolders.remove(packageName); if (changed) { writeAsyncLocked(); scheduleWriteFileLocked(); } return true; } } /** * Schedule writing the state to file. */ @GuardedBy("RoleManagerService.mLock") private void writeAsyncLocked() { @GuardedBy("mLock") private void scheduleWriteFileLocked() { throwIfDestroyedLocked(); ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>(); for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) { String roleName = mRoles.keyAt(i); ArraySet<String> roleHolders = mRoles.valueAt(i); roleHolders = new ArraySet<>(roleHolders); roles.put(roleName, roleHolders); } long currentTimeMillis = System.currentTimeMillis(); long writeDelayMillis; if (!mWriteHandler.hasMessagesOrCallbacks()) { Loading @@ -311,14 +309,26 @@ public class RoleUserState { } } mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeSync, this, mVersion, mPackagesHash, roles), writeDelayMillis); mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeFile, this), writeDelayMillis); Slog.i(LOG_TAG, "Scheduled writing roles.xml"); } @WorkerThread private void writeSync(int version, @Nullable String packagesHash, @NonNull ArrayMap<String, ArraySet<String>> roles) { private void writeFile() { int version; String packagesHash; ArrayMap<String, ArraySet<String>> roles; synchronized (mLock) { if (mDestroyed) { return; } version = mVersion; packagesHash = mPackagesHash; roles = snapshotRolesLocked(); } AtomicFile atomicFile = new AtomicFile(getFile(mUserId), "roles-" + mUserId); FileOutputStream out = null; try { Loading Loading @@ -385,8 +395,8 @@ public class RoleUserState { /** * Read the state from file. */ @GuardedBy("RoleManagerService.mLock") private void readLocked() { private void readFile() { synchronized (mLock) { File file = getFile(mUserId); try (FileInputStream in = new AtomicFile(file).openRead()) { XmlPullParser parser = Xml.newPullParser(); Loading @@ -399,6 +409,7 @@ public class RoleUserState { throw new IllegalStateException("Failed to parse roles.xml: " + file, e); } } } private void parseXmlLocked(@NonNull XmlPullParser parser) throws IOException, XmlPullParserException { Loading Loading @@ -470,20 +481,28 @@ public class RoleUserState { * * @param dumpOutputStream the output stream to dump to */ @GuardedBy("RoleManagerService.mLock") public void dumpLocked(@NonNull DualDumpOutputStream dumpOutputStream, @NonNull String fieldName, long fieldId) { public void dump(@NonNull DualDumpOutputStream dumpOutputStream, @NonNull String fieldName, long fieldId) { int version; String packagesHash; ArrayMap<String, ArraySet<String>> roles; synchronized (mLock) { throwIfDestroyedLocked(); version = mVersion; packagesHash = mPackagesHash; roles = snapshotRolesLocked(); } long fieldToken = dumpOutputStream.start(fieldName, fieldId); dumpOutputStream.write("user_id", RoleUserStateProto.USER_ID, mUserId); dumpOutputStream.write("version", RoleUserStateProto.VERSION, mVersion); dumpOutputStream.write("packages_hash", RoleUserStateProto.PACKAGES_HASH, mPackagesHash); dumpOutputStream.write("version", RoleUserStateProto.VERSION, version); dumpOutputStream.write("packages_hash", RoleUserStateProto.PACKAGES_HASH, packagesHash); int rolesSize = mRoles.size(); int rolesSize = roles.size(); for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) { String roleName = mRoles.keyAt(rolesIndex); ArraySet<String> roleHolders = mRoles.valueAt(rolesIndex); String roleName = roles.keyAt(rolesIndex); ArraySet<String> roleHolders = roles.valueAt(rolesIndex); long rolesToken = dumpOutputStream.start("roles", RoleUserStateProto.ROLES); dumpOutputStream.write("name", RoleProto.NAME, roleName); Loading @@ -501,19 +520,33 @@ public class RoleUserState { dumpOutputStream.end(fieldToken); } @GuardedBy("mLock") private ArrayMap<String, ArraySet<String>> snapshotRolesLocked() { ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>(); for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) { String roleName = mRoles.keyAt(i); ArraySet<String> roleHolders = mRoles.valueAt(i); roleHolders = new ArraySet<>(roleHolders); roles.put(roleName, roleHolders); } return roles; } /** * Destroy this state and delete the corresponding file. Any pending writes to the file will be * cancelled and any future interaction with this state will throw an exception. */ @GuardedBy("RoleManagerService.mLock") public void destroyLocked() { public void destroy() { synchronized (mLock) { throwIfDestroyedLocked(); mWriteHandler.removeCallbacksAndMessages(null); getFile(mUserId).delete(); mDestroyed = true; } } @GuardedBy("RoleManagerService.mLock") @GuardedBy("mLock") private void throwIfDestroyedLocked() { if (mDestroyed) { throw new IllegalStateException("This RoleUserState has already been destroyed"); Loading