Merge "Further refactor UidPermissionState and GIDs."
This commit is contained in:
committed by
Android (Google) Code Review
commit
bf3fcf6ade
@@ -46,6 +46,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
@@ -55,7 +56,6 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -95,7 +95,7 @@ public class SystemConfig {
|
||||
private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku";
|
||||
|
||||
// Group-ids that are given to all packages as read from etc/permissions/*.xml.
|
||||
int[] mGlobalGids;
|
||||
int[] mGlobalGids = EmptyArray.INT;
|
||||
|
||||
// These are the built-in uid -> permission mappings that were read from the
|
||||
// system configuration files.
|
||||
|
||||
@@ -36,13 +36,14 @@ import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.server.pm.DumpState;
|
||||
import com.android.server.pm.PackageManagerService;
|
||||
import com.android.server.pm.PackageSettingBase;
|
||||
import com.android.server.pm.parsing.PackageInfoUtils;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
@@ -95,7 +96,8 @@ public final class BasePermission {
|
||||
int uid;
|
||||
|
||||
/** Additional GIDs given to apps granted this permission */
|
||||
private int[] gids;
|
||||
@NonNull
|
||||
private int[] gids = EmptyArray.INT;
|
||||
|
||||
/**
|
||||
* Flag indicating that {@link #gids} should be adjusted based on the
|
||||
@@ -132,7 +134,7 @@ public final class BasePermission {
|
||||
public int getUid() {
|
||||
return uid;
|
||||
}
|
||||
public void setGids(int[] gids, boolean perUser) {
|
||||
public void setGids(@NonNull int[] gids, boolean perUser) {
|
||||
this.gids = gids;
|
||||
this.perUser = perUser;
|
||||
}
|
||||
@@ -141,18 +143,20 @@ public final class BasePermission {
|
||||
}
|
||||
|
||||
public boolean hasGids() {
|
||||
return !ArrayUtils.isEmpty(gids);
|
||||
return gids.length != 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public int[] computeGids(int userId) {
|
||||
if (perUser) {
|
||||
final int[] userGids = new int[gids.length];
|
||||
for (int i = 0; i < gids.length; i++) {
|
||||
userGids[i] = UserHandle.getUid(userId, gids[i]);
|
||||
final int gid = gids[i];
|
||||
userGids[i] = UserHandle.getUid(userId, gid);
|
||||
}
|
||||
return userGids;
|
||||
} else {
|
||||
return gids;
|
||||
return gids.length != 0 ? gids.clone() : gids;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +295,8 @@ public final class BasePermission {
|
||||
pendingPermissionInfo.packageName = newPackageName;
|
||||
}
|
||||
uid = 0;
|
||||
setGids(null, false);
|
||||
gids = EmptyArray.INT;
|
||||
perUser = false;
|
||||
}
|
||||
|
||||
public boolean addToTree(@ProtectionLevel int protectionLevel,
|
||||
|
||||
@@ -55,7 +55,6 @@ import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING
|
||||
import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
|
||||
import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
|
||||
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
|
||||
import static com.android.server.pm.permission.UidPermissionState.PERMISSION_OPERATION_FAILURE;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
@@ -154,6 +153,8 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal.Permiss
|
||||
import com.android.server.policy.PermissionPolicyInternal;
|
||||
import com.android.server.policy.SoftRestrictedPermissionPolicy;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -247,6 +248,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
private final SparseArray<ArraySet<String>> mSystemPermissions;
|
||||
|
||||
/** Built-in group IDs given to all packages. Read from system configuration files. */
|
||||
@NonNull
|
||||
private final int[] mGlobalGids;
|
||||
|
||||
private final HandlerThread mHandlerThread;
|
||||
@@ -1513,7 +1515,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
// normal runtime permissions. For now they apply to all users.
|
||||
// TODO(zhanghai): We are breaking the behavior above by making all permission state
|
||||
// per-user. It isn't documented behavior and relatively rarely used anyway.
|
||||
if (uidState.grantPermission(bp) != PERMISSION_OPERATION_FAILURE) {
|
||||
if (uidState.grantPermission(bp)) {
|
||||
if (callback != null) {
|
||||
callback.onInstallPermissionGranted();
|
||||
}
|
||||
@@ -1531,18 +1533,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
final int result = uidState.grantPermission(bp);
|
||||
switch (result) {
|
||||
case PERMISSION_OPERATION_FAILURE: {
|
||||
return;
|
||||
}
|
||||
if (!uidState.grantPermission(bp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
case UidPermissionState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
|
||||
if (callback != null) {
|
||||
callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId);
|
||||
}
|
||||
if (bp.hasGids()) {
|
||||
if (callback != null) {
|
||||
callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (bp.isRuntime()) {
|
||||
@@ -1662,7 +1660,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
// normal runtime permissions. For now they apply to all users.
|
||||
// TODO(zhanghai): We are breaking the behavior above by making all permission state
|
||||
// per-user. It isn't documented behavior and relatively rarely used anyway.
|
||||
if (uidState.revokePermission(bp) != PERMISSION_OPERATION_FAILURE) {
|
||||
if (uidState.revokePermission(bp)) {
|
||||
if (callback != null) {
|
||||
mDefaultPermissionCallback.onInstallPermissionRevoked();
|
||||
}
|
||||
@@ -1670,12 +1668,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
// Permission is already revoked, no need to do anything.
|
||||
if (!uidState.isPermissionGranted(permName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (uidState.revokePermission(bp) == PERMISSION_OPERATION_FAILURE) {
|
||||
if (!uidState.revokePermission(bp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2525,11 +2518,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NonNull
|
||||
private int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) {
|
||||
BasePermission permission = mSettings.getPermission(permissionName);
|
||||
if (permission == null) {
|
||||
return null;
|
||||
return EmptyArray.INT;
|
||||
}
|
||||
return permission.computeGids(userId);
|
||||
}
|
||||
@@ -2650,8 +2643,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
uidState.setGlobalGids(mGlobalGids);
|
||||
|
||||
ArraySet<String> newImplicitPermissions = new ArraySet<>();
|
||||
final String friendlyName = pkg.getPackageName() + "(" + pkg.getUid() + ")";
|
||||
|
||||
@@ -2786,7 +2777,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
switch (grant) {
|
||||
case GRANT_INSTALL: {
|
||||
// Grant an install permission.
|
||||
if (uidState.grantPermission(bp) != PERMISSION_OPERATION_FAILURE) {
|
||||
if (uidState.grantPermission(bp)) {
|
||||
changedInstallPermission = true;
|
||||
}
|
||||
} break;
|
||||
@@ -2818,8 +2809,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
if (permissionPolicyInitialized && hardRestricted) {
|
||||
if (!restrictionExempt) {
|
||||
if (origPermState != null && origPermState.isGranted()
|
||||
&& uidState.revokePermission(
|
||||
bp) != PERMISSION_OPERATION_FAILURE) {
|
||||
&& uidState.revokePermission(bp)) {
|
||||
wasChanged = true;
|
||||
}
|
||||
if (!restrictionApplied) {
|
||||
@@ -2851,8 +2841,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
|| (!hardRestricted || restrictionExempt)) {
|
||||
if ((origPermState != null && origPermState.isGranted())
|
||||
|| upgradedActivityRecognitionPermission != null) {
|
||||
if (uidState.grantPermission(bp)
|
||||
== PERMISSION_OPERATION_FAILURE) {
|
||||
if (!uidState.grantPermission(bp)) {
|
||||
wasChanged = true;
|
||||
}
|
||||
}
|
||||
@@ -2871,8 +2860,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
}
|
||||
|
||||
if (!uidState.isPermissionGranted(bp.name)
|
||||
&& uidState.grantPermission(bp)
|
||||
!= PERMISSION_OPERATION_FAILURE) {
|
||||
&& uidState.grantPermission(bp)) {
|
||||
wasChanged = true;
|
||||
}
|
||||
|
||||
@@ -2920,13 +2908,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
} break;
|
||||
}
|
||||
} else {
|
||||
if (uidState.revokePermission(bp) != PERMISSION_OPERATION_FAILURE) {
|
||||
// Also drop the permission flags.
|
||||
uidState.updatePermissionFlags(bp,
|
||||
MASK_PERMISSION_FLAGS_ALL, 0);
|
||||
changedInstallPermission = true;
|
||||
if (DEBUG_PERMISSIONS) {
|
||||
Slog.i(TAG, "Un-granting permission " + perm
|
||||
if (DEBUG_PERMISSIONS) {
|
||||
boolean wasGranted = uidState.isPermissionGranted(bp.name);
|
||||
if (wasGranted || bp.isAppOp()) {
|
||||
Slog.i(TAG, (wasGranted ? "Un-granting" : "Not granting")
|
||||
+ " permission " + perm
|
||||
+ " from package " + friendlyName
|
||||
+ " (protectionLevel=" + bp.getProtectionLevel()
|
||||
+ " flags=0x"
|
||||
@@ -2934,20 +2920,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
ps))
|
||||
+ ")");
|
||||
}
|
||||
} else if (bp.isAppOp()) {
|
||||
// Don't print warning for app op permissions, since it is fine for them
|
||||
// not to be granted, there is a UI for the user to decide.
|
||||
if (DEBUG_PERMISSIONS
|
||||
&& (packageOfInterest == null
|
||||
|| packageOfInterest.equals(pkg.getPackageName()))) {
|
||||
Slog.i(TAG, "Not granting permission " + perm
|
||||
+ " to package " + friendlyName
|
||||
+ " (protectionLevel=" + bp.getProtectionLevel()
|
||||
+ " flags=0x"
|
||||
+ Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg,
|
||||
ps))
|
||||
+ ")");
|
||||
}
|
||||
}
|
||||
if (uidState.removePermissionState(bp.name)) {
|
||||
changedInstallPermission = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3026,8 +3001,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
|
||||
if ((flags & BLOCKING_PERMISSION_FLAGS) == 0
|
||||
&& supportsRuntimePermissions) {
|
||||
int revokeResult = ps.revokePermission(bp);
|
||||
if (revokeResult != PERMISSION_OPERATION_FAILURE) {
|
||||
if (ps.revokePermission(bp)) {
|
||||
if (DEBUG_PERMISSIONS) {
|
||||
Slog.i(TAG, "Revoking runtime permission "
|
||||
+ permission + " for " + pkgName
|
||||
@@ -3895,14 +3869,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
// The package is gone - no need to keep flags for applying policy.
|
||||
uidState.updatePermissionFlags(bp, PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
|
||||
|
||||
// Try to revoke as a runtime permission which is per user.
|
||||
// TODO(zhanghai): This doesn't make sense. revokePermission() doesn't fail, and why are
|
||||
// we only killing the uid when gids changed, instead of any permission change?
|
||||
if (uidState.revokePermission(bp)
|
||||
== UidPermissionState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
|
||||
// TODO(zhanghai): Why are we only killing the UID when GIDs changed, instead of any
|
||||
// permission change?
|
||||
if (uidState.removePermissionState(bp.name) && bp.hasGids()) {
|
||||
affectedUserId = userId;
|
||||
}
|
||||
}
|
||||
@@ -3935,17 +3904,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
boolean runtimePermissionChanged = false;
|
||||
|
||||
// Prune permissions
|
||||
final List<com.android.server.pm.permission.PermissionState> permissionStates =
|
||||
uidState.getPermissionStates();
|
||||
final List<PermissionState> permissionStates = uidState.getPermissionStates();
|
||||
final int permissionStatesSize = permissionStates.size();
|
||||
for (int i = permissionStatesSize - 1; i >= 0; i--) {
|
||||
PermissionState permissionState = permissionStates.get(i);
|
||||
if (!usedPermissions.contains(permissionState.getName())) {
|
||||
BasePermission bp = mSettings.getPermissionLocked(permissionState.getName());
|
||||
if (bp != null) {
|
||||
uidState.revokePermission(bp);
|
||||
uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL, 0);
|
||||
if (permissionState.isRuntime()) {
|
||||
if (uidState.removePermissionState(bp.name) && permissionState.isRuntime()) {
|
||||
runtimePermissionChanged = true;
|
||||
}
|
||||
}
|
||||
@@ -4208,11 +4174,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
+ p.getPackageName() + " and user " + userId);
|
||||
return;
|
||||
}
|
||||
if (uidState.getPermissionState(bp.getName()) != null) {
|
||||
uidState.revokePermission(bp);
|
||||
uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL,
|
||||
0);
|
||||
}
|
||||
uidState.removePermissionState(bp.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -4771,7 +4733,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID " + userId);
|
||||
return EMPTY_INT_ARRAY;
|
||||
}
|
||||
return uidState.computeGids(userId);
|
||||
return uidState.computeGids(mGlobalGids, userId);
|
||||
}
|
||||
|
||||
private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
|
||||
@@ -4834,7 +4796,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
@UserIdInt int userId) {
|
||||
return PermissionManagerService.this.getGrantedPermissions(packageName, userId);
|
||||
}
|
||||
@Nullable
|
||||
@NonNull
|
||||
@Override
|
||||
public int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) {
|
||||
return PermissionManagerService.this.getPermissionGids(permissionName, userId);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.server.pm.permission;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -62,7 +61,7 @@ public final class PermissionState {
|
||||
return mPermission.getName();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NonNull
|
||||
public int[] computeGids(@UserIdInt int userId) {
|
||||
return mPermission.computeGids(userId);
|
||||
}
|
||||
|
||||
@@ -22,35 +22,19 @@ import android.annotation.UserIdInt;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.IntArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Permission state for a UID.
|
||||
* <p>
|
||||
* This class is also responsible for keeping track of the Linux GIDs per
|
||||
* user for a package or a shared user. The GIDs are computed as a set of
|
||||
* the GIDs for all granted permissions' GIDs on a per user basis.
|
||||
*/
|
||||
public final class UidPermissionState {
|
||||
/** The permission operation failed. */
|
||||
public static final int PERMISSION_OPERATION_FAILURE = -1;
|
||||
|
||||
/** The permission operation succeeded and no gids changed. */
|
||||
public static final int PERMISSION_OPERATION_SUCCESS = 0;
|
||||
|
||||
/** The permission operation succeeded and gids changed. */
|
||||
public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 1;
|
||||
|
||||
private static final int[] NO_GIDS = {};
|
||||
|
||||
@NonNull
|
||||
private final Object mLock = new Object();
|
||||
|
||||
@@ -60,11 +44,6 @@ public final class UidPermissionState {
|
||||
@Nullable
|
||||
private ArrayMap<String, PermissionState> mPermissions;
|
||||
|
||||
private boolean mPermissionReviewRequired;
|
||||
|
||||
@NonNull
|
||||
private int[] mGlobalGids = NO_GIDS;
|
||||
|
||||
public UidPermissionState() {}
|
||||
|
||||
public UidPermissionState(@NonNull UidPermissionState other) {
|
||||
@@ -80,12 +59,6 @@ public final class UidPermissionState {
|
||||
mPermissions.put(name, new PermissionState(permissionState));
|
||||
}
|
||||
}
|
||||
|
||||
mPermissionReviewRequired = other.mPermissionReviewRequired;
|
||||
|
||||
if (other.mGlobalGids != NO_GIDS) {
|
||||
mGlobalGids = other.mGlobalGids.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,8 +69,6 @@ public final class UidPermissionState {
|
||||
synchronized (mLock) {
|
||||
mMissing = false;
|
||||
mPermissions = null;
|
||||
mPermissionReviewRequired = false;
|
||||
mGlobalGids = NO_GIDS;
|
||||
invalidateCache();
|
||||
}
|
||||
}
|
||||
@@ -156,8 +127,8 @@ public final class UidPermissionState {
|
||||
/**
|
||||
* Gets the state for a permission or null if none.
|
||||
*
|
||||
* @param name the permission name.
|
||||
* @return the permission state.
|
||||
* @param name the permission name
|
||||
* @return the permission state
|
||||
*/
|
||||
@Nullable
|
||||
public PermissionState getPermissionState(@NonNull String name) {
|
||||
@@ -169,6 +140,22 @@ public final class UidPermissionState {
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private PermissionState getOrCreatePermissionState(@NonNull BasePermission permission) {
|
||||
synchronized (mLock) {
|
||||
if (mPermissions == null) {
|
||||
mPermissions = new ArrayMap<>();
|
||||
}
|
||||
final String name = permission.getName();
|
||||
PermissionState permissionState = mPermissions.get(name);
|
||||
if (permissionState == null) {
|
||||
permissionState = new PermissionState(permission);
|
||||
mPermissions.put(name, permissionState);
|
||||
}
|
||||
return permissionState;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all permission states.
|
||||
*
|
||||
@@ -186,19 +173,44 @@ public final class UidPermissionState {
|
||||
|
||||
/**
|
||||
* Put a permission state.
|
||||
*
|
||||
* @param permission the permission
|
||||
* @param granted whether the permission is granted
|
||||
* @param flags the permission flags
|
||||
*/
|
||||
public void putPermissionState(@NonNull BasePermission permission, boolean isGranted,
|
||||
int flags) {
|
||||
public void putPermissionState(@NonNull BasePermission permission, boolean granted, int flags) {
|
||||
synchronized (mLock) {
|
||||
ensureNoPermissionState(permission.name);
|
||||
PermissionState permissionState = ensurePermissionState(permission);
|
||||
if (isGranted) {
|
||||
final String name = permission.getName();
|
||||
if (mPermissions == null) {
|
||||
mPermissions = new ArrayMap<>();
|
||||
} else {
|
||||
mPermissions.remove(name);
|
||||
}
|
||||
final PermissionState permissionState = new PermissionState(permission);
|
||||
if (granted) {
|
||||
permissionState.grant();
|
||||
}
|
||||
permissionState.updateFlags(flags, flags);
|
||||
if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
|
||||
mPermissionReviewRequired = true;
|
||||
mPermissions.put(name, permissionState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a permission state.
|
||||
*
|
||||
* @param name the permission name
|
||||
* @return whether the permission state changed
|
||||
*/
|
||||
public boolean removePermissionState(@NonNull String name) {
|
||||
synchronized (mLock) {
|
||||
if (mPermissions == null) {
|
||||
return false;
|
||||
}
|
||||
boolean changed = mPermissions.remove(name) != null;
|
||||
if (changed && mPermissions.isEmpty()) {
|
||||
mPermissions = null;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,13 +221,8 @@ public final class UidPermissionState {
|
||||
* @return whether the permission is granted
|
||||
*/
|
||||
public boolean isPermissionGranted(@NonNull String name) {
|
||||
synchronized (mLock) {
|
||||
if (mPermissions == null) {
|
||||
return false;
|
||||
}
|
||||
PermissionState permissionState = mPermissions.get(name);
|
||||
return permissionState != null && permissionState.isGranted();
|
||||
}
|
||||
final PermissionState permissionState = getPermissionState(name);
|
||||
return permissionState != null && permissionState.isGranted();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,61 +253,37 @@ public final class UidPermissionState {
|
||||
/**
|
||||
* Grant a permission.
|
||||
*
|
||||
* @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}.
|
||||
* @param permission the permission to grant
|
||||
* @return whether the permission grant state changed
|
||||
*/
|
||||
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;
|
||||
public boolean grantPermission(@NonNull BasePermission permission) {
|
||||
PermissionState permissionState = getOrCreatePermissionState(permission);
|
||||
return permissionState.grant();
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a permission.
|
||||
*
|
||||
* @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}.
|
||||
* @return whether the permission grant state changed
|
||||
*/
|
||||
public int revokePermission(@NonNull BasePermission permission) {
|
||||
public boolean revokePermission(@NonNull BasePermission permission) {
|
||||
final String name = permission.getName();
|
||||
if (!isPermissionGranted(name)) {
|
||||
return PERMISSION_OPERATION_SUCCESS;
|
||||
final PermissionState permissionState = getPermissionState(name);
|
||||
if (permissionState == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PermissionState permissionState;
|
||||
synchronized (mLock) {
|
||||
permissionState = mPermissions.get(name);
|
||||
final boolean changed = permissionState.revoke();
|
||||
if (changed && permissionState.isDefault()) {
|
||||
removePermissionState(name);
|
||||
}
|
||||
|
||||
if (!permissionState.revoke()) {
|
||||
return PERMISSION_OPERATION_FAILURE;
|
||||
}
|
||||
|
||||
if (permissionState.isDefault()) {
|
||||
ensureNoPermissionState(name);
|
||||
}
|
||||
|
||||
return permission.hasGids() ? PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED
|
||||
: PERMISSION_OPERATION_SUCCESS;
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the flags for a permission.
|
||||
*
|
||||
* @param name the permission name.
|
||||
* @param name the permission name
|
||||
* @return the permission flags
|
||||
*/
|
||||
public int getPermissionFlags(@NonNull String name) {
|
||||
@@ -324,76 +307,36 @@ public final class UidPermissionState {
|
||||
if (flagMask == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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();
|
||||
if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0
|
||||
&& (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
|
||||
mPermissionReviewRequired = true;
|
||||
} else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0
|
||||
&& (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
|
||||
if (mPermissionReviewRequired && !hasPermissionRequiringReview()) {
|
||||
mPermissionReviewRequired = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
final PermissionState permissionState = getOrCreatePermissionState(permission);
|
||||
final boolean changed = permissionState.updateFlags(flagMask, flagValues);
|
||||
if (changed && permissionState.isDefault()) {
|
||||
removePermissionState(permission.name);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public boolean updatePermissionFlagsForAllPermissions(int flagMask, int flagValues) {
|
||||
if (flagMask == 0) {
|
||||
return false;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
if (mPermissions == null) {
|
||||
return false;
|
||||
}
|
||||
boolean changed = false;
|
||||
final int permissionsSize = mPermissions.size();
|
||||
for (int i = 0; i < permissionsSize; i++) {
|
||||
boolean anyChanged = false;
|
||||
for (int i = mPermissions.size() - 1; i >= 0; i--) {
|
||||
final PermissionState permissionState = mPermissions.valueAt(i);
|
||||
changed |= permissionState.updateFlags(flagMask, flagValues);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private PermissionState ensurePermissionState(@NonNull BasePermission permission) {
|
||||
final String name = permission.getName();
|
||||
synchronized (mLock) {
|
||||
if (mPermissions == null) {
|
||||
mPermissions = new ArrayMap<>();
|
||||
}
|
||||
PermissionState permissionState = mPermissions.get(name);
|
||||
if (permissionState == null) {
|
||||
permissionState = new PermissionState(permission);
|
||||
mPermissions.put(name, permissionState);
|
||||
}
|
||||
return permissionState;
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureNoPermissionState(@NonNull String name) {
|
||||
synchronized (mLock) {
|
||||
if (mPermissions == null) {
|
||||
return;
|
||||
}
|
||||
mPermissions.remove(name);
|
||||
if (mPermissions.isEmpty()) {
|
||||
mPermissions = null;
|
||||
final boolean changed = permissionState.updateFlags(flagMask, flagValues);
|
||||
if (changed && permissionState.isDefault()) {
|
||||
mPermissions.removeAt(i);
|
||||
}
|
||||
anyChanged |= changed;
|
||||
}
|
||||
return anyChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPermissionReviewRequired() {
|
||||
return mPermissionReviewRequired;
|
||||
}
|
||||
|
||||
private boolean hasPermissionRequiringReview() {
|
||||
synchronized (mLock) {
|
||||
final int permissionsSize = mPermissions.size();
|
||||
for (int i = 0; i < permissionsSize; i++) {
|
||||
@@ -406,27 +349,6 @@ public final class UidPermissionState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the global gids, applicable to all users.
|
||||
*/
|
||||
@NonNull
|
||||
public int[] getGlobalGids() {
|
||||
return mGlobalGids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the global gids, applicable to all users.
|
||||
*
|
||||
* @param globalGids The global gids.
|
||||
*/
|
||||
public void setGlobalGids(@NonNull int[] globalGids) {
|
||||
if (!ArrayUtils.isEmpty(globalGids)) {
|
||||
mGlobalGids = Arrays.copyOf(globalGids, globalGids.length);
|
||||
} else {
|
||||
mGlobalGids = NO_GIDS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the Linux GIDs from the permissions granted to a user.
|
||||
*
|
||||
@@ -434,54 +356,25 @@ public final class UidPermissionState {
|
||||
* @return the GIDs for the user
|
||||
*/
|
||||
@NonNull
|
||||
public int[] computeGids(@UserIdInt int userId) {
|
||||
int[] gids = mGlobalGids;
|
||||
|
||||
public int[] computeGids(@NonNull int[] globalGids, @UserIdInt int userId) {
|
||||
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);
|
||||
}
|
||||
IntArray gids = IntArray.wrap(globalGids);
|
||||
if (mPermissions == null) {
|
||||
return gids.toArray();
|
||||
}
|
||||
final int permissionsSize = mPermissions.size();
|
||||
for (int i = 0; i < permissionsSize; i++) {
|
||||
PermissionState permissionState = mPermissions.valueAt(i);
|
||||
if (!permissionState.isGranted()) {
|
||||
continue;
|
||||
}
|
||||
final int[] permissionGids = permissionState.computeGids(userId);
|
||||
if (permissionGids.length != 0) {
|
||||
gids.addAll(permissionGids);
|
||||
}
|
||||
}
|
||||
return gids.toArray();
|
||||
}
|
||||
|
||||
return gids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the Linux GIDs from the permissions granted to specified users.
|
||||
*
|
||||
* @param userIds the user IDs
|
||||
* @return the GIDs for the user
|
||||
*/
|
||||
@NonNull
|
||||
public int[] computeGids(@NonNull int[] userIds) {
|
||||
int[] gids = mGlobalGids;
|
||||
|
||||
for (final int userId : userIds) {
|
||||
final int[] userGids = computeGids(userId);
|
||||
gids = appendInts(gids, userGids);
|
||||
}
|
||||
|
||||
return gids;
|
||||
}
|
||||
|
||||
// TODO: fix this to use arraycopy and append all ints in one go
|
||||
private static int[] appendInts(int[] current, int[] added) {
|
||||
if (current != null && added != null) {
|
||||
for (int guid : added) {
|
||||
current = ArrayUtils.appendInt(current, guid);
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
static void invalidateCache() {
|
||||
|
||||
Reference in New Issue
Block a user