summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hai Zhang <zhanghai@google.com> 2020-09-25 14:47:34 -0700
committer Hai Zhang <zhanghai@google.com> 2020-09-25 16:09:44 -0700
commit4280835e64ebac2fa87ca586aefd90fa7f63d0a2 (patch)
treeea762e76dab38c2a6f926cbf48d4222d5f95c9d7
parentb66035bb44b5505e12adb5107837966c09d5f6b8 (diff)
Refactor UidPermissionState.
Renamed hasPermission() to isPermissionGranted(), hasRequestedPermission() to hasPermissionState(), and re-ordered the fields and methods. No behavioral change is expected. Bug: 158736025 Test: presubmit Change-Id: Iecfc9d0b66ab95625e26476b80dca116f247c0b2
-rw-r--r--services/core/java/com/android/server/pm/permission/BasePermission.java3
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java30
-rw-r--r--services/core/java/com/android/server/pm/permission/UidPermissionState.java563
3 files changed, 267 insertions, 329 deletions
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 865b8a1e97eb..524f9acf15cd 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -425,8 +425,7 @@ public final class BasePermission {
public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg,
UidPermissionState uidState) {
- int index = pkg.getRequestedPermissions().indexOf(name);
- if (!uidState.hasRequestedPermission(name) && index == -1) {
+ if (!uidState.hasPermissionState(name) && !pkg.getRequestedPermissions().contains(name)) {
throw new SecurityException("Package " + pkg.getPackageName()
+ " has not requested permission " + name);
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 840b233902f6..474ce7c32c5a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -943,7 +943,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private boolean checkSinglePermissionInternal(int uid,
@NonNull UidPermissionState uidState, @NonNull String permissionName) {
- if (!uidState.hasPermission(permissionName)) {
+ if (!uidState.isPermissionGranted(permissionName)) {
return false;
}
@@ -1659,7 +1659,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
// Permission is already revoked, no need to do anything.
- if (!uidState.hasPermission(permName)) {
+ if (!uidState.isPermissionGranted(permName)) {
return;
}
@@ -2482,12 +2482,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return Collections.emptySet();
}
if (!ps.getInstantApp(userId)) {
- return uidState.getPermissions();
+ return uidState.getGrantedPermissions();
} else {
// Install permission state is shared among all users, but instant app state is
// per-user, so we can only filter it here unless we make install permission state
// per-user as well.
- final Set<String> instantPermissions = new ArraySet<>(uidState.getPermissions());
+ final Set<String> instantPermissions = new ArraySet<>(uidState.getGrantedPermissions());
instantPermissions.removeIf(permissionName -> {
BasePermission permission = mSettings.getPermission(permissionName);
if (permission == null) {
@@ -2660,7 +2660,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Cache newImplicitPermissions before modifing permissionsState as for the shared
// uids the original and new state are the same object
- if (!origState.hasRequestedPermission(permName)
+ if (!origState.hasPermissionState(permName)
&& (pkg.getImplicitPermissions().contains(permName)
|| (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
if (pkg.getImplicitPermissions().contains(permName)) {
@@ -2685,7 +2685,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum);
String splitPermName = sp.getSplitPermission();
if (sp.getNewPermissions().contains(permName)
- && origState.hasPermission(splitPermName)) {
+ && origState.isPermissionGranted(splitPermName)) {
upgradedActivityRecognitionPermission = splitPermName;
newImplicitPermissions.add(permName);
@@ -2741,7 +2741,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- if (grant == GRANT_INSTALL && !allowedSig && !origState.hasPermission(perm)) {
+ if (grant == GRANT_INSTALL && !allowedSig && !origState.isPermissionGranted(perm)) {
// If this is an existing, non-system package, then
// we can't add any new permissions to it. Runtime
// permissions can be added any time - they are dynamic.
@@ -2849,7 +2849,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- if (!uidState.hasPermission(bp.name)
+ if (!uidState.isPermissionGranted(bp.name)
&& uidState.grantPermission(bp)
!= PERMISSION_OPERATION_FAILURE) {
wasChanged = true;
@@ -2993,7 +2993,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean supportsRuntimePermissions = pkg.getTargetSdkVersion()
>= Build.VERSION_CODES.M;
- for (String permission : ps.getPermissions()) {
+ for (String permission : ps.getGrantedPermissions()) {
if (!pkg.getImplicitPermissions().contains(permission)) {
BasePermission bp = mSettings.getPermissionLocked(permission);
if (bp.isRuntime()) {
@@ -3050,7 +3050,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
int numSourcePerm = sourcePerms.size();
for (int i = 0; i < numSourcePerm; i++) {
String sourcePerm = sourcePerms.valueAt(i);
- if (ps.hasPermission(sourcePerm)) {
+ if (ps.isPermissionGranted(sourcePerm)) {
if (!isGranted) {
flags = 0;
}
@@ -3155,7 +3155,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
- if (!origPs.hasRequestedPermission(sourcePerms)) {
+ if (!origPs.hasPermissionState(sourcePerms)) {
boolean inheritsFromInstallPerm = false;
for (int sourcePermNum = 0; sourcePermNum < sourcePerms.size();
sourcePermNum++) {
@@ -3465,7 +3465,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!allowed && bp.isDevelopment()) {
// For development permissions, a development permission
// is granted only if it was already granted.
- allowed = origPermissions.hasPermission(perm);
+ allowed = origPermissions.isPermissionGranted(perm);
}
if (!allowed && bp.isSetup()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
@@ -3687,7 +3687,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
continue;
}
- if (uidState.hasPermission(permissionName)) {
+ if (uidState.isPermissionGranted(permissionName)) {
if (oldGrantedRestrictedPermissions.get(userId) == null) {
oldGrantedRestrictedPermissions.put(userId, new ArraySet<>());
}
@@ -3749,7 +3749,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// as whitelisting trumps policy i.e. policy cannot grant a non
// grantable permission.
if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
- final boolean isGranted = uidState.hasPermission(permissionName);
+ final boolean isGranted = uidState.isPermissionGranted(permissionName);
if (!isWhitelisted && isGranted) {
mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -3791,7 +3791,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
+ " and user " + userId);
continue;
}
- if (!newUidState.hasPermission(permission)) {
+ if (!newUidState.isPermissionGranted(permission)) {
callback.onPermissionRevoked(pkg.getUid(), userId, null);
break;
}
diff --git a/services/core/java/com/android/server/pm/permission/UidPermissionState.java b/services/core/java/com/android/server/pm/permission/UidPermissionState.java
index b45176b720b5..06a7f8dbd2be 100644
--- a/services/core/java/com/android/server/pm/permission/UidPermissionState.java
+++ b/services/core/java/com/android/server/pm/permission/UidPermissionState.java
@@ -54,149 +54,161 @@ public final class UidPermissionState {
@NonNull
private final Object mLock = new Object();
+ private boolean mMissing;
+
@GuardedBy("mLock")
+ @Nullable
private ArrayMap<String, PermissionState> mPermissions;
+ private boolean mPermissionReviewRequired;
+
@NonNull
private int[] mGlobalGids = NO_GIDS;
- private boolean mMissing;
+ public UidPermissionState() {}
- private boolean mPermissionReviewRequired;
+ public UidPermissionState(@NonNull UidPermissionState other) {
+ synchronized (mLock) {
+ mMissing = other.mMissing;
- public UidPermissionState() {
- /* do nothing */
- }
+ if (other.mPermissions != null) {
+ mPermissions = new ArrayMap<>();
+ final int permissionsSize = other.mPermissions.size();
+ for (int i = 0; i < permissionsSize; i++) {
+ final String name = other.mPermissions.keyAt(i);
+ final PermissionState permissionState = other.mPermissions.valueAt(i);
+ mPermissions.put(name, new PermissionState(permissionState));
+ }
+ }
+
+ mPermissionReviewRequired = other.mPermissionReviewRequired;
- public UidPermissionState(@NonNull UidPermissionState prototype) {
- copyFrom(prototype);
+ if (other.mGlobalGids != NO_GIDS) {
+ mGlobalGids = other.mGlobalGids.clone();
+ }
+ }
}
/**
- * Gets the global gids, applicable to all users.
+ * Reset the internal state of this object.
*/
- @NonNull
- public int[] getGlobalGids() {
- return mGlobalGids;
+ public void reset() {
+ synchronized (mLock) {
+ mMissing = false;
+ mPermissions = null;
+ mPermissionReviewRequired = false;
+ mGlobalGids = NO_GIDS;
+ invalidateCache();
+ }
}
/**
- * Sets the global gids, applicable to all users.
- *
- * @param globalGids The global gids.
+ * Check whether the permissions state is missing for a user. This can happen if permission
+ * state is rolled back and we'll need to generate a reasonable default state to keep the app
+ * usable.
*/
- public void setGlobalGids(@NonNull int[] globalGids) {
- if (!ArrayUtils.isEmpty(globalGids)) {
- mGlobalGids = Arrays.copyOf(globalGids, globalGids.length);
- }
+ public boolean isMissing() {
+ return mMissing;
}
- static void invalidateCache() {
- PackageManager.invalidatePackageInfoCache();
+ /**
+ * Set whether the permissions state is missing for a user. This can happen if permission state
+ * is rolled back and we'll need to generate a reasonable default state to keep the app usable.
+ */
+ public void setMissing(boolean missing) {
+ mMissing = missing;
}
/**
- * Initialized this instance from another one.
+ * Get whether there is a permission state for a permission.
*
- * @param other The other instance.
+ * @deprecated This used to be named hasRequestedPermission() and its usage is confusing
*/
- public void copyFrom(@NonNull UidPermissionState other) {
- if (other == this) {
- return;
+ @Deprecated
+ public boolean hasPermissionState(@NonNull String name) {
+ synchronized (mLock) {
+ return mPermissions != null && mPermissions.containsKey(name);
}
+ }
+ /**
+ * Get whether there is a permission state for any of the permissions.
+ *
+ * @deprecated This used to be named hasRequestedPermission() and its usage is confusing
+ */
+ @Deprecated
+ public boolean hasPermissionState(@NonNull ArraySet<String> names) {
synchronized (mLock) {
- if (mPermissions != null) {
- if (other.mPermissions == null) {
- mPermissions = null;
- } else {
- mPermissions.clear();
- }
+ if (mPermissions == null) {
+ return false;
}
- if (other.mPermissions != null) {
- if (mPermissions == null) {
- mPermissions = new ArrayMap<>();
- }
- final int permissionCount = other.mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- String name = other.mPermissions.keyAt(i);
- PermissionState permissionState = other.mPermissions.valueAt(i);
- mPermissions.put(name, new PermissionState(permissionState));
+ final int namesSize = names.size();
+ for (int i = 0; i < namesSize; i++) {
+ final String name = names.valueAt(i);
+ if (mPermissions.containsKey(name)) {
+ return true;
}
}
- }
-
- mGlobalGids = NO_GIDS;
- if (other.mGlobalGids != NO_GIDS) {
- mGlobalGids = other.mGlobalGids.clone();
- }
-
- mMissing = other.mMissing;
-
- mPermissionReviewRequired = other.mPermissionReviewRequired;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
return false;
}
- if (getClass() != obj.getClass()) {
- return false;
- }
- final UidPermissionState other = (UidPermissionState) obj;
+ }
+ /**
+ * Gets the state for a permission or null if none.
+ *
+ * @param name the permission name.
+ * @return the permission state.
+ */
+ @Nullable
+ public PermissionState getPermissionState(@NonNull String name) {
synchronized (mLock) {
if (mPermissions == null) {
- if (other.mPermissions != null) {
- return false;
- }
- } else if (!mPermissions.equals(other.mPermissions)) {
- return false;
+ return null;
}
+ return mPermissions.get(name);
}
-
- if (mMissing != other.mMissing) {
- return false;
- }
-
- if (mPermissionReviewRequired != other.mPermissionReviewRequired) {
- return false;
- }
- return Arrays.equals(mGlobalGids, other.mGlobalGids);
}
/**
- * Check whether the permissions state is missing for a user. This can happen if permission
- * state is rolled back and we'll need to generate a reasonable default state to keep the app
- * usable.
+ * Get all permission states.
+ *
+ * @return the permission states
*/
- public boolean isMissing() {
- return mMissing;
+ @NonNull
+ public List<PermissionState> getPermissionStates() {
+ synchronized (mLock) {
+ if (mPermissions == null) {
+ return Collections.emptyList();
+ }
+ return new ArrayList<>(mPermissions.values());
+ }
}
/**
- * Set whether the permissions state is missing for a user. This can happen if permission state
- * is rolled back and we'll need to generate a reasonable default state to keep the app usable.
+ * Put a permission state.
*/
- public void setMissing(boolean missing) {
- mMissing = missing;
- }
-
- public boolean isPermissionReviewRequired() {
- return mPermissionReviewRequired;
+ public void putPermissionState(@NonNull BasePermission permission, boolean isGranted,
+ int flags) {
+ synchronized (mLock) {
+ ensureNoPermissionState(permission.name);
+ PermissionState permissionState = ensurePermissionState(permission);
+ if (isGranted) {
+ permissionState.grant();
+ }
+ permissionState.updateFlags(flags, flags);
+ if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+ mPermissionReviewRequired = true;
+ }
+ }
}
/**
- * Gets whether the state has a given permission.
+ * Get whether a permission is granted.
*
- * @param name The permission name.
- * @return Whether the state has the permission.
+ * @param name the permission name
+ * @return whether the permission is granted
*/
- public boolean hasPermission(@NonNull String name) {
+ public boolean isPermissionGranted(@NonNull String name) {
synchronized (mLock) {
if (mPermissions == null) {
return false;
@@ -207,86 +219,105 @@ public final class UidPermissionState {
}
/**
- * Returns whether the state has any known request for the given permission name,
- * whether or not it has been granted.
+ * Get all the granted permissions.
*
- * @deprecated Not all requested permissions may be here.
+ * @return the granted permissions
*/
- @Deprecated
- public boolean hasRequestedPermission(@NonNull ArraySet<String> names) {
+ @NonNull
+ public Set<String> getGrantedPermissions() {
synchronized (mLock) {
if (mPermissions == null) {
- return false;
+ return Collections.emptySet();
}
- for (int i = names.size() - 1; i >= 0; i--) {
- if (mPermissions.get(names.valueAt(i)) != null) {
- return true;
+
+ Set<String> permissions = new ArraySet<>(mPermissions.size());
+ final int permissionsSize = mPermissions.size();
+ for (int i = 0; i < permissionsSize; i++) {
+ PermissionState permissionState = mPermissions.valueAt(i);
+
+ if (permissionState.isGranted()) {
+ permissions.add(permissionState.getName());
}
}
+ return permissions;
}
-
- return false;
}
/**
- * Returns whether the state has any known request for the given permission name,
- * whether or not it has been granted.
+ * Grant a permission.
*
- * @deprecated Not all requested permissions may be here.
+ * @param permission the permission to grantt
+ * @return the operation result, which is either {@link #PERMISSION_OPERATION_SUCCESS},
+ * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
+ * #PERMISSION_OPERATION_FAILURE}.
*/
- @Deprecated
- public boolean hasRequestedPermission(@NonNull String name) {
- return mPermissions != null && (mPermissions.get(name) != null);
+ public int grantPermission(@NonNull BasePermission permission) {
+ if (isPermissionGranted(permission.getName())) {
+ return PERMISSION_OPERATION_SUCCESS;
+ }
+
+ PermissionState permissionState = ensurePermissionState(permission);
+
+ if (!permissionState.grant()) {
+ return PERMISSION_OPERATION_FAILURE;
+ }
+
+ return permission.hasGids() ? PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED
+ : PERMISSION_OPERATION_SUCCESS;
}
/**
- * Gets all permissions for a given device user id regardless if they
- * are install time or runtime permissions.
+ * Revoke a permission.
*
- * @return The permissions or an empty set.
+ * @param permission the permission to revoke
+ * @return the operation result, which is either {@link #PERMISSION_OPERATION_SUCCESS},
+ * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
+ * #PERMISSION_OPERATION_FAILURE}.
*/
- @NonNull
- public Set<String> getPermissions() {
- synchronized (mLock) {
- if (mPermissions == null) {
- return Collections.emptySet();
- }
-
- Set<String> permissions = new ArraySet<>(mPermissions.size());
+ public int revokePermission(@NonNull BasePermission permission) {
+ final String name = permission.getName();
+ if (!isPermissionGranted(name)) {
+ return PERMISSION_OPERATION_SUCCESS;
+ }
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- String permission = mPermissions.keyAt(i);
+ PermissionState permissionState;
+ synchronized (mLock) {
+ permissionState = mPermissions.get(name);
+ }
- if (hasPermission(permission)) {
- permissions.add(permission);
- }
- }
+ if (!permissionState.revoke()) {
+ return PERMISSION_OPERATION_FAILURE;
+ }
- return permissions;
+ if (permissionState.isDefault()) {
+ ensureNoPermissionState(name);
}
+
+ return permission.hasGids() ? PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED
+ : PERMISSION_OPERATION_SUCCESS;
}
/**
- * Gets the flags for a permission.
+ * Get the flags for a permission.
*
- * @param name The permission name.
- * @return The permission state or null if no such.
+ * @param name the permission name.
+ * @return the permission flags
*/
public int getPermissionFlags(@NonNull String name) {
- PermissionState permState = getPermissionState(name);
- if (permState != null) {
- return permState.getFlags();
+ final PermissionState permissionState = getPermissionState(name);
+ if (permissionState == null) {
+ return 0;
}
- return 0;
+ return permissionState.getFlags();
}
/**
- * Update the flags associated with a given permission.
- * @param permission The permission whose flags to update.
- * @param flagMask Mask for which flags to change.
- * @param flagValues New values for the mask flags.
- * @return Whether the permission flags changed.
+ * Update the flags for a permission.
+ *
+ * @param permission the permission name
+ * @param flagMask the mask for the flags
+ * @param flagValues the new values for the masked flags
+ * @return whether the permission flags changed
*/
public boolean updatePermissionFlags(@NonNull BasePermission permission, int flagMask,
int flagValues) {
@@ -294,11 +325,10 @@ public final class UidPermissionState {
return false;
}
- PermissionState permissionState = ensurePermissionState(permission);
-
- final int oldFlags = permissionState.getFlags();
-
synchronized (mLock) {
+ final PermissionState permissionState = ensurePermissionState(permission);
+ final int oldFlags = permissionState.getFlags();
+
final boolean updated = permissionState.updateFlags(flagMask, flagValues);
if (updated) {
final int newFlags = permissionState.getFlags();
@@ -316,199 +346,132 @@ public final class UidPermissionState {
}
}
- private boolean hasPermissionRequiringReview() {
- synchronized (mLock) {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- final PermissionState permission = mPermissions.valueAt(i);
- if ((permission.getFlags() & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- return true;
- }
- }
- }
- return false;
- }
-
public boolean updatePermissionFlagsForAllPermissions(int flagMask, int flagValues) {
synchronized (mLock) {
if (mPermissions == null) {
return false;
}
boolean changed = false;
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- PermissionState permissionState = mPermissions.valueAt(i);
+ final int permissionsSize = mPermissions.size();
+ for (int i = 0; i < permissionsSize; i++) {
+ final PermissionState permissionState = mPermissions.valueAt(i);
changed |= permissionState.updateFlags(flagMask, flagValues);
}
return changed;
}
}
- /**
- * Compute the Linux gids for a given device user from the permissions
- * granted to this user. Note that these are computed to avoid additional
- * state as they are rarely accessed.
- *
- * @param userId The device user id.
- * @return The gids for the device user.
- */
@NonNull
- public int[] computeGids(@UserIdInt int userId) {
- int[] gids = mGlobalGids;
-
+ private PermissionState ensurePermissionState(@NonNull BasePermission permission) {
+ final String name = permission.getName();
synchronized (mLock) {
- if (mPermissions != null) {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- PermissionState permissionState = mPermissions.valueAt(i);
- if (!permissionState.isGranted()) {
- continue;
- }
- final int[] permGids = permissionState.computeGids(userId);
- if (permGids != NO_GIDS) {
- gids = appendInts(gids, permGids);
- }
- }
+ if (mPermissions == null) {
+ mPermissions = new ArrayMap<>();
}
+ PermissionState permissionState = mPermissions.get(name);
+ if (permissionState == null) {
+ permissionState = new PermissionState(permission);
+ mPermissions.put(name, permissionState);
+ }
+ return permissionState;
}
-
- return gids;
- }
-
- /**
- * Compute the Linux gids for all device users from the permissions
- * granted to these users.
- *
- * @return The gids for all device users.
- */
- @NonNull
- public int[] computeGids(@NonNull int[] userIds) {
- int[] gids = mGlobalGids;
-
- for (int userId : userIds) {
- final int[] userGids = computeGids(userId);
- gids = appendInts(gids, userGids);
- }
-
- return gids;
}
- /**
- * Resets the internal state of this object.
- */
- public void reset() {
- mGlobalGids = NO_GIDS;
-
+ private void ensureNoPermissionState(@NonNull String name) {
synchronized (mLock) {
- mPermissions = null;
- invalidateCache();
+ if (mPermissions == null) {
+ return;
+ }
+ mPermissions.remove(name);
+ if (mPermissions.isEmpty()) {
+ mPermissions = null;
+ }
}
+ }
- mMissing = false;
- mPermissionReviewRequired = false;
+ public boolean isPermissionReviewRequired() {
+ return mPermissionReviewRequired;
}
- /**
- * Gets the state for a permission or null if no such.
- *
- * @param name The permission name.
- * @return The permission state.
- */
- @Nullable
- public PermissionState getPermissionState(@NonNull String name) {
+ private boolean hasPermissionRequiringReview() {
synchronized (mLock) {
- if (mPermissions == null) {
- return null;
+ final int permissionsSize = mPermissions.size();
+ for (int i = 0; i < permissionsSize; i++) {
+ final PermissionState permission = mPermissions.valueAt(i);
+ if ((permission.getFlags() & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+ return true;
+ }
}
- return mPermissions.get(name);
+ return false;
}
}
/**
- * Gets all permission states.
- *
- * @return The permission states or an empty set.
+ * Gets the global gids, applicable to all users.
*/
@NonNull
- public List<PermissionState> getPermissionStates() {
- synchronized (mLock) {
- if (mPermissions == null) {
- return Collections.emptyList();
- }
- return new ArrayList<>(mPermissions.values());
- }
+ public int[] getGlobalGids() {
+ return mGlobalGids;
}
/**
- * Put a permission state.
+ * Sets the global gids, applicable to all users.
+ *
+ * @param globalGids The global gids.
*/
- public void putPermissionState(@NonNull BasePermission permission, boolean isGranted,
- int flags) {
- synchronized (mLock) {
- ensureNoPermissionState(permission.name);
- PermissionState permissionState = ensurePermissionState(permission);
- if (isGranted) {
- permissionState.grant();
- }
- permissionState.updateFlags(flags, flags);
- if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- mPermissionReviewRequired = true;
- }
+ public void setGlobalGids(@NonNull int[] globalGids) {
+ if (!ArrayUtils.isEmpty(globalGids)) {
+ mGlobalGids = Arrays.copyOf(globalGids, globalGids.length);
+ } else {
+ mGlobalGids = NO_GIDS;
}
}
/**
- * Grant a permission.
+ * Compute the Linux GIDs from the permissions granted to a user.
*
- * @param permission The permission to grant.
- * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
- * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
- * #PERMISSION_OPERATION_FAILURE}.
+ * @param userId the user ID
+ * @return the GIDs for the user
*/
- public int grantPermission(@NonNull BasePermission permission) {
- if (hasPermission(permission.getName())) {
- return PERMISSION_OPERATION_SUCCESS;
- }
-
- PermissionState permissionState = ensurePermissionState(permission);
+ @NonNull
+ public int[] computeGids(@UserIdInt int userId) {
+ int[] gids = mGlobalGids;
- if (!permissionState.grant()) {
- return PERMISSION_OPERATION_FAILURE;
+ synchronized (mLock) {
+ if (mPermissions != null) {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ PermissionState permissionState = mPermissions.valueAt(i);
+ if (!permissionState.isGranted()) {
+ continue;
+ }
+ final int[] permGids = permissionState.computeGids(userId);
+ if (permGids != NO_GIDS) {
+ gids = appendInts(gids, permGids);
+ }
+ }
+ }
}
- return permission.hasGids() ? PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED
- : PERMISSION_OPERATION_SUCCESS;
+ return gids;
}
/**
- * Revoke a permission.
+ * Compute the Linux GIDs from the permissions granted to specified users.
*
- * @param permission The permission to revoke.
- * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
- * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
- * #PERMISSION_OPERATION_FAILURE}.
+ * @param userIds the user IDs
+ * @return the GIDs for the user
*/
- public int revokePermission(@NonNull BasePermission permission) {
- final String permissionName = permission.getName();
- if (!hasPermission(permissionName)) {
- return PERMISSION_OPERATION_SUCCESS;
- }
-
- PermissionState permissionState;
- synchronized (mLock) {
- permissionState = mPermissions.get(permissionName);
- }
-
- if (!permissionState.revoke()) {
- return PERMISSION_OPERATION_FAILURE;
- }
+ @NonNull
+ public int[] computeGids(@NonNull int[] userIds) {
+ int[] gids = mGlobalGids;
- if (permissionState.isDefault()) {
- ensureNoPermissionState(permissionName);
+ for (final int userId : userIds) {
+ final int[] userGids = computeGids(userId);
+ gids = appendInts(gids, userGids);
}
- return permission.hasGids() ? PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED
- : PERMISSION_OPERATION_SUCCESS;
+ return gids;
}
// TODO: fix this to use arraycopy and append all ints in one go
@@ -521,31 +484,7 @@ public final class UidPermissionState {
return current;
}
- @NonNull
- private PermissionState ensurePermissionState(@NonNull BasePermission permission) {
- final String permissionName = permission.getName();
- synchronized (mLock) {
- if (mPermissions == null) {
- mPermissions = new ArrayMap<>();
- }
- PermissionState permissionState = mPermissions.get(permissionName);
- if (permissionState == null) {
- permissionState = new PermissionState(permission);
- mPermissions.put(permissionName, permissionState);
- }
- return permissionState;
- }
- }
-
- private void ensureNoPermissionState(@NonNull String name) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return;
- }
- mPermissions.remove(name);
- if (mPermissions.isEmpty()) {
- mPermissions = null;
- }
- }
+ static void invalidateCache() {
+ PackageManager.invalidatePackageInfoCache();
}
}