Add role initialization to RoleControllerService.
This change adds RoleManager.setRoleNamesFromController() to allow
RoleControllerService to initialize the roles for a user. This change
also fixes the persistence of roles by calling writeAsyncLocked().
Bug: 110557011
Test: build
Change-Id: I921b6aa691478ca4c0dd1a75fc929a96ce1e7df5
diff --git a/api/system-current.txt b/api/system-current.txt
index ee767af0..f8bb3c4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -867,6 +867,7 @@
method public java.util.List<java.lang.String> getRoleHoldersAsUser(java.lang.String, android.os.UserHandle);
method public void removeRoleHolderAsUser(java.lang.String, java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
method public boolean removeRoleHolderFromController(java.lang.String, java.lang.String);
+ method public void setRoleNamesFromController(java.util.List<java.lang.String>);
field public static final java.lang.String EXTRA_REQUEST_ROLE_NAME = "android.app.role.extra.REQUEST_ROLE_NAME";
}
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index 2cf13ec2..3ca8ec0 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -37,6 +37,8 @@
void clearRoleHoldersAsUser(in String roleName, int userId, in IRoleManagerCallback callback);
+ void setRoleNamesFromController(in List<String> roleNames);
+
boolean addRoleHolderFromController(in String roleName, in String packageName);
boolean removeRoleHolderFromController(in String roleName, in String packageName);
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index ef86b01..20e7f27 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -92,8 +92,8 @@
*
* @hide
*/
- public static final String PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER =
- "com.android.permissioncontroller.permission.MANAGE_ROLE_HOLDERS_FROM_CONTROLLER";
+ public static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER =
+ "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER";
@NonNull
private final Context mContext;
@@ -342,12 +342,36 @@
}
/**
+ * Set the names of all the available roles. Should only be called from
+ * {@link android.rolecontrollerservice.RoleControllerService}.
+ * <p>
+ * <strong>Note:</strong> Using this API requires holding
+ * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
+ *
+ * @param roleNames the names of all the available roles
+ *
+ * @throws IllegalArgumentException if the list of role names is {@code null}.
+ *
+ * @hide
+ */
+ @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
+ @SystemApi
+ public void setRoleNamesFromController(@NonNull List<String> roleNames) {
+ Preconditions.checkNotNull(roleNames, "roleNames cannot be null");
+ try {
+ mService.setRoleNamesFromController(roleNames);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Add a specific application to the holders of a role, only modifying records inside
* {@link RoleManager}. Should only be called from
* {@link android.rolecontrollerservice.RoleControllerService}.
* <p>
* <strong>Note:</strong> Using this API requires holding
- * {@link #PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER}.
+ * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
*
* @param roleName the name of the role to add the role holder for
* @param packageName the package name of the application to add to the role holders
@@ -362,7 +386,7 @@
*
* @hide
*/
- @RequiresPermission(PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER)
+ @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
@SystemApi
public boolean addRoleHolderFromController(@NonNull String roleName,
@NonNull String packageName) {
@@ -381,7 +405,7 @@
* {@link android.rolecontrollerservice.RoleControllerService}.
* <p>
* <strong>Note:</strong> Using this API requires holding
- * {@link #PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER}.
+ * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
*
* @param roleName the name of the role to remove the role holder for
* @param packageName the package name of the application to remove from the role holders
@@ -396,7 +420,7 @@
*
* @hide
*/
- @RequiresPermission(PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER)
+ @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
@SystemApi
public boolean removeRoleHolderFromController(@NonNull String roleName,
@NonNull String packageName) {
diff --git a/services/core/java/com/android/server/role/RemoteRoleControllerService.java b/services/core/java/com/android/server/role/RemoteRoleControllerService.java
index 538f4cf..cb89780 100644
--- a/services/core/java/com/android/server/role/RemoteRoleControllerService.java
+++ b/services/core/java/com/android/server/role/RemoteRoleControllerService.java
@@ -48,6 +48,7 @@
static final boolean DEBUG = false;
private static final String LOG_TAG = RemoteRoleControllerService.class.getSimpleName();
+ // TODO: STOPSHIP: This isn't the right thread, as we are also using it to write to disk.
@NonNull
private static final Handler sCallbackHandler = BackgroundThread.getHandler();
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index d01e762..4124210 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -284,12 +284,26 @@
}
@Override
+ public void setRoleNamesFromController(@NonNull List<String> roleNames) {
+ Preconditions.checkNotNull(roleNames, "roleNames cannot be null");
+ getContext().enforceCallingOrSelfPermission(
+ RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
+ "setRoleNamesFromController");
+
+ int userId = UserHandle.getCallingUserId();
+ synchronized (mLock) {
+ RoleUserState userState = getUserStateLocked(userId);
+ userState.setRoleNamesLocked(roleNames);
+ }
+ }
+
+ @Override
public boolean addRoleHolderFromController(@NonNull String roleName,
@NonNull String packageName) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
getContext().enforceCallingOrSelfPermission(
- RoleManager.PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER,
+ RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"addRoleHolderFromController");
int userId = UserHandle.getCallingUserId();
@@ -305,7 +319,7 @@
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
getContext().enforceCallingOrSelfPermission(
- RoleManager.PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER,
+ RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"removeRoleHolderFromController");
int userId = UserHandle.getCallingUserId();
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 68e737e..9c43f4d 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -45,6 +45,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.List;
/**
* Stores the state of roles for a user.
@@ -101,7 +102,11 @@
@GuardedBy("RoleManagerService.mLock")
public void setVersionLocked(int version) {
throwIfDestroyedLocked();
+ if (mVersion == version) {
+ return;
+ }
mVersion = version;
+ writeAsyncLocked();
}
/**
@@ -132,6 +137,41 @@
}
/**
+ * Set the names of all available roles.
+ *
+ * @param roleNames the names of all the available roles
+ */
+ @GuardedBy("RoleManagerService.mLock")
+ public void setRoleNamesLocked(@NonNull List<String> roleNames) {
+ throwIfDestroyedLocked();
+ boolean changed = false;
+ for (int i = mRoles.size() - 1; i >= 0; i--) {
+ String roleName = mRoles.keyAt(i);
+ 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: "
+ + roleName + ", holders: " + packageNames);
+ }
+ mRoles.removeAt(i);
+ changed = true;
+ }
+ }
+ int roleNamesSize = roleNames.size();
+ for (int i = 0; i < roleNamesSize; i++) {
+ String roleName = roleNames.get(i);
+ if (!mRoles.containsKey(roleName)) {
+ mRoles.put(roleName, new ArraySet<>());
+ Slog.i(LOG_TAG, "Added new role: " + roleName);
+ changed = true;
+ }
+ }
+ if (changed) {
+ writeAsyncLocked();
+ }
+ }
+
+ /**
* Add a holder to a role.
*
* @param roleName the name of the role to add the holder to
@@ -150,7 +190,10 @@
+ ", package: " + packageName);
return false;
}
- roleHolders.add(packageName);
+ boolean changed = roleHolders.add(packageName);
+ if (changed) {
+ writeAsyncLocked();
+ }
return true;
}
@@ -173,7 +216,10 @@
+ ", package: " + packageName);
return false;
}
- roleHolders.remove(packageName);
+ boolean changed = roleHolders.remove(packageName);
+ if (changed) {
+ writeAsyncLocked();
+ }
return true;
}
@@ -181,7 +227,7 @@
* Schedule writing the state to file.
*/
@GuardedBy("RoleManagerService.mLock")
- public void writeAsyncLocked() {
+ private void writeAsyncLocked() {
throwIfDestroyedLocked();
int version = mVersion;
ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
@@ -192,6 +238,7 @@
roles.put(roleName, roleHolders);
}
mWriteHandler.removeCallbacksAndMessages(null);
+ // TODO: Throttle writes.
mWriteHandler.sendMessage(PooledLambda.obtainMessage(
RoleUserState::writeSync, this, version, roles));
}