Merge "Use the service lock for permission state."

This commit is contained in:
Hai Zhang
2020-10-09 00:33:42 +00:00
committed by Android (Google) Code Review
5 changed files with 504 additions and 542 deletions

View File

@@ -433,18 +433,6 @@ public final class BasePermission {
throw new SecurityException("No permission tree found for " + permName);
}
public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg,
UidPermissionState uidState) {
if (!uidState.hasPermissionState(name) && !pkg.getRequestedPermissions().contains(name)) {
throw new SecurityException("Package " + pkg.getPackageName()
+ " has not requested permission " + name);
}
if (!isRuntime() && !isDevelopment()) {
throw new SecurityException("Permission " + name + " requested by "
+ pkg.getPackageName() + " is not a changeable permission type");
}
}
private static BasePermission findPermissionTree(
Collection<BasePermission> permissionTrees, String permName) {
for (BasePermission bp : permissionTrees) {

View File

@@ -21,57 +21,38 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
/**
* Permission state for this device.
*/
public final class DevicePermissionState {
@GuardedBy("mLock")
@NonNull
private final SparseArray<UserPermissionState> mUserStates = new SparseArray<>();
@NonNull
private final Object mLock;
public DevicePermissionState(@NonNull Object lock) {
mLock = lock;
}
@Nullable
public UserPermissionState getUserState(@UserIdInt int userId) {
synchronized (mLock) {
return mUserStates.get(userId);
}
return mUserStates.get(userId);
}
@NonNull
public UserPermissionState getOrCreateUserState(@UserIdInt int userId) {
synchronized (mLock) {
UserPermissionState userState = mUserStates.get(userId);
if (userState == null) {
userState = new UserPermissionState(mLock);
mUserStates.put(userId, userState);
}
return userState;
UserPermissionState userState = mUserStates.get(userId);
if (userState == null) {
userState = new UserPermissionState();
mUserStates.put(userId, userState);
}
return userState;
}
public void removeUserState(@UserIdInt int userId) {
synchronized (mLock) {
mUserStates.delete(userId);
}
mUserStates.delete(userId);
}
public int[] getUserIds() {
synchronized (mLock) {
final int userStatesSize = mUserStates.size();
final int[] userIds = new int[userStatesSize];
for (int i = 0; i < userStatesSize; i++) {
final int userId = mUserStates.keyAt(i);
userIds[i] = userId;
}
return userIds;
final int userStatesSize = mUserStates.size();
final int[] userIds = new int[userStatesSize];
for (int i = 0; i < userStatesSize; i++) {
final int userId = mUserStates.keyAt(i);
userIds[i] = userId;
}
return userIds;
}
}

View File

@@ -216,8 +216,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
/** Internal connection to the user manager */
private final UserManagerInternal mUserManagerInt;
@GuardedBy("mLock")
@NonNull
private final DevicePermissionState mState;
private final DevicePermissionState mState = new DevicePermissionState();
/** Permission controller: User space permission management */
private PermissionControllerManager mPermissionControllerManager;
@@ -386,7 +387,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
mUserManagerInt = LocalServices.getService(UserManagerInternal.class);
mSettings = new PermissionSettings(mLock);
mState = new DevicePermissionState(mLock);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mHandlerThread = new ServiceThread(TAG,
@@ -665,20 +665,23 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (pkg == null) {
return 0;
}
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
return 0;
}
synchronized (mLock) {
if (mSettings.getPermissionLocked(permName) == null) {
return 0;
}
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
return 0;
}
return uidState.getPermissionFlags(permName);
}
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
return 0;
}
final UidPermissionState uidState = getUidState(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
return 0;
}
return uidState.getPermissionFlags(permName);
}
@Override
@@ -772,52 +775,52 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
final BasePermission bp;
synchronized (mLock) {
bp = mSettings.getPermissionLocked(permName);
boolean isRequested = false;
// Fast path, the current package has requested the permission.
if (pkg.getRequestedPermissions().contains(permName)) {
isRequested = true;
}
if (bp == null) {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
if (bp.isInstallerExemptIgnored()) {
flagValues &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
}
final UidPermissionState uidState = getUidState(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
return;
}
final boolean hadState = uidState.getPermissionState(permName) != null;
if (!hadState) {
boolean isRequested = false;
// Fast path, the current package has requested the permission.
if (pkg.getRequestedPermissions().contains(permName)) {
isRequested = true;
}
if (!isRequested) {
// Slow path, go through all shared user packages.
String[] sharedUserPackageNames =
mPackageManagerInt.getSharedUserPackagesForPackage(packageName, userId);
for (String sharedUserPackageName : sharedUserPackageNames) {
AndroidPackage sharedUserPkg = mPackageManagerInt.getPackage(
sharedUserPackageName);
if (sharedUserPkg != null
&& sharedUserPkg.getRequestedPermissions().contains(permName)) {
isRequested = true;
break;
}
if (!isRequested) {
// Slow path, go through all shared user packages.
String[] sharedUserPackageNames =
mPackageManagerInt.getSharedUserPackagesForPackage(packageName, userId);
for (String sharedUserPackageName : sharedUserPackageNames) {
AndroidPackage sharedUserPkg = mPackageManagerInt.getPackage(
sharedUserPackageName);
if (sharedUserPkg != null
&& sharedUserPkg.getRequestedPermissions().contains(permName)) {
isRequested = true;
break;
}
}
if (!isRequested) {
}
final BasePermission bp;
final boolean permissionUpdated;
synchronized (mLock) {
bp = mSettings.getPermissionLocked(permName);
if (bp == null) {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
if (bp.isInstallerExemptIgnored()) {
flagValues &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
}
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
return;
}
if (!uidState.hasPermissionState(permName) && !isRequested) {
Log.e(TAG, "Permission " + permName + " isn't requested by package " + packageName);
return;
}
permissionUpdated = uidState.updatePermissionFlags(bp, flagMask, flagValues);
}
final boolean permissionUpdated =
uidState.updatePermissionFlags(bp, flagMask, flagValues);
if (permissionUpdated && bp.isRuntime()) {
notifyRuntimePermissionStateChanged(packageName, userId);
}
@@ -861,14 +864,17 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final boolean[] changed = new boolean[1];
mPackageManagerInt.forEachPackage(pkg -> {
final UidPermissionState uidState = getUidState(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return;
synchronized (mLock) {
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG,
"Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return;
}
changed[0] |= uidState.updatePermissionFlagsForAllPermissions(
effectiveFlagMask, effectiveFlagValues);
}
changed[0] |= uidState.updatePermissionFlagsForAllPermissions(
effectiveFlagMask, effectiveFlagValues);
mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid());
});
@@ -920,33 +926,37 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
final int uid = UserHandle.getUid(userId, pkg.getUid());
final UidPermissionState uidState = getUidState(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return PackageManager.PERMISSION_DENIED;
}
final boolean isInstantApp = mPackageManagerInt.getInstantAppPackageName(uid) != null;
if (checkSinglePermissionInternal(uid, uidState, permissionName)) {
return PackageManager.PERMISSION_GRANTED;
}
synchronized (mLock) {
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return PackageManager.PERMISSION_DENIED;
}
final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
if (fullerPermissionName != null
&& checkSinglePermissionInternal(uid, uidState, fullerPermissionName)) {
return PackageManager.PERMISSION_GRANTED;
if (checkSinglePermissionInternalLocked(uidState, permissionName, isInstantApp)) {
return PackageManager.PERMISSION_GRANTED;
}
final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
if (fullerPermissionName != null && checkSinglePermissionInternalLocked(uidState,
fullerPermissionName, isInstantApp)) {
return PackageManager.PERMISSION_GRANTED;
}
}
return PackageManager.PERMISSION_DENIED;
}
private boolean checkSinglePermissionInternal(int uid,
@NonNull UidPermissionState uidState, @NonNull String permissionName) {
private boolean checkSinglePermissionInternalLocked(@NonNull UidPermissionState uidState,
@NonNull String permissionName, boolean isInstantApp) {
if (!uidState.isPermissionGranted(permissionName)) {
return false;
}
if (mPackageManagerInt.getInstantAppPackageName(uid) != null) {
if (isInstantApp) {
return mSettings.isPermissionInstant(permissionName);
}
@@ -994,24 +1004,25 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return checkPermissionInternal(pkg, false, permissionName, userId);
}
if (checkSingleUidPermissionInternal(uid, permissionName)) {
return PackageManager.PERMISSION_GRANTED;
}
synchronized (mLock) {
if (checkSingleUidPermissionInternalLocked(uid, permissionName)) {
return PackageManager.PERMISSION_GRANTED;
}
final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
if (fullerPermissionName != null
&& checkSingleUidPermissionInternal(uid, fullerPermissionName)) {
return PackageManager.PERMISSION_GRANTED;
final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
if (fullerPermissionName != null
&& checkSingleUidPermissionInternalLocked(uid, fullerPermissionName)) {
return PackageManager.PERMISSION_GRANTED;
}
}
return PackageManager.PERMISSION_DENIED;
}
private boolean checkSingleUidPermissionInternal(int uid, @NonNull String permissionName) {
synchronized (mLock) {
ArraySet<String> permissions = mSystemPermissions.get(uid);
return permissions != null && permissions.contains(permissionName);
}
private boolean checkSingleUidPermissionInternalLocked(int uid,
@NonNull String permissionName) {
ArraySet<String> permissions = mSystemPermissions.get(uid);
return permissions != null && permissions.contains(permissionName);
}
@Override
@@ -1137,42 +1148,45 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final long identity = Binder.clearCallingIdentity();
try {
final UidPermissionState uidState = getUidState(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
return null;
}
int queryFlags = 0;
if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0) {
queryFlags |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
}
if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
queryFlags |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
}
if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
queryFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
}
if ((flags & PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE) != 0) {
queryFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
}
ArrayList<String> whitelistedPermissions = null;
final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
for (int i = 0; i < permissionCount; i++) {
final String permissionName = pkg.getRequestedPermissions().get(i);
final int currentFlags =
uidState.getPermissionFlags(permissionName);
if ((currentFlags & queryFlags) != 0) {
if (whitelistedPermissions == null) {
whitelistedPermissions = new ArrayList<>();
}
whitelistedPermissions.add(permissionName);
synchronized (mLock) {
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + packageName + " and user "
+ userId);
return null;
}
}
return whitelistedPermissions;
int queryFlags = 0;
if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0) {
queryFlags |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
}
if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
queryFlags |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
}
if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
queryFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
}
if ((flags & PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE) != 0) {
queryFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
}
ArrayList<String> whitelistedPermissions = null;
final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
for (int i = 0; i < permissionCount; i++) {
final String permissionName = pkg.getRequestedPermissions().get(i);
final int currentFlags =
uidState.getPermissionFlags(permissionName);
if ((currentFlags & queryFlags) != 0) {
if (whitelistedPermissions == null) {
whitelistedPermissions = new ArrayList<>();
}
whitelistedPermissions.add(permissionName);
}
}
return whitelistedPermissions;
}
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1437,12 +1451,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
"grantRuntimePermission");
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
packageName);
final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName);
if (pkg == null || ps == null) {
Log.e(TAG, "Unknown package: " + packageName);
return;
}
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
final BasePermission bp;
synchronized (mLock) {
bp = mSettings.getPermissionLocked(permName);
@@ -1450,46 +1467,17 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (bp == null) {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
final UidPermissionState uidState = getUidState(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return;
if (!(bp.isRuntime() || bp.isDevelopment())) {
throw new SecurityException("Permission " + permName + " requested by "
+ pkg.getPackageName() + " is not a changeable permission type");
}
bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, uidState);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
// to keep the review required permission flag per user while an
// install permission's state is shared across all users.
if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
&& bp.isRuntime()) {
return;
}
final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
final int flags = uidState.getPermissionFlags(permName);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
Log.e(TAG, "Cannot grant system fixed permission "
+ permName + " for package " + packageName);
return;
}
if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
Log.e(TAG, "Cannot grant policy fixed permission "
+ permName + " for package " + packageName);
return;
}
if (bp.isHardRestricted()
&& (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
Log.e(TAG, "Cannot grant hard restricted non-exempt permission "
+ permName + " for package " + packageName);
if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime()) {
return;
}
@@ -1501,36 +1489,61 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return;
}
if (bp.isDevelopment()) {
// Development permissions must be handled specially, since they are not
// 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)) {
if (callback != null) {
callback.onInstallPermissionGranted();
}
synchronized (mLock) {
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return;
}
return;
}
if (ps.getInstantApp(userId) && !bp.isInstant()) {
throw new SecurityException("Cannot grant non-ephemeral permission"
+ permName + " for package " + packageName);
}
if (!(uidState.hasPermissionState(permName)
|| pkg.getRequestedPermissions().contains(permName))) {
throw new SecurityException("Package " + pkg.getPackageName()
+ " has not requested permission " + permName);
}
if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
return;
}
final int flags = uidState.getPermissionFlags(permName);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
Log.e(TAG, "Cannot grant system fixed permission "
+ permName + " for package " + packageName);
return;
}
if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
Log.e(TAG, "Cannot grant policy fixed permission "
+ permName + " for package " + packageName);
return;
}
if (!uidState.grantPermission(bp)) {
return;
}
if (bp.isHardRestricted()
&& (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
Log.e(TAG, "Cannot grant hard restricted non-exempt permission "
+ permName + " for package " + packageName);
return;
}
if (bp.hasGids()) {
if (callback != null) {
callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId);
if (bp.isDevelopment()) {
// Development permissions must be handled specially, since they are not
// 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)) {
return;
}
} else {
if (ps.getInstantApp(userId) && !bp.isInstant()) {
throw new SecurityException("Cannot grant non-ephemeral permission" + permName
+ " for package " + packageName);
}
if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
return;
}
if (!uidState.grantPermission(bp)) {
return;
}
}
}
@@ -1538,8 +1551,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
logPermission(MetricsEvent.ACTION_PERMISSION_GRANTED, permName, packageName);
}
final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
if (callback != null) {
callback.onPermissionGranted(uid, userId);
if (bp.isDevelopment()) {
callback.onInstallPermissionGranted();
} else {
callback.onPermissionGranted(uid, userId);
}
if (bp.hasGids()) {
callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId);
}
}
if (bp.isRuntime()) {
@@ -1593,56 +1614,57 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
final BasePermission bp = mSettings.getPermissionLocked(permName);
final BasePermission bp = mSettings.getPermission(permName);
if (bp == null) {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
final UidPermissionState uidState = getUidState(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return;
if (!(bp.isRuntime() || bp.isDevelopment())) {
throw new SecurityException("Permission " + permName + " requested by "
+ pkg.getPackageName() + " is not a changeable permission type");
}
bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, uidState);
synchronized (mLock) {
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return;
}
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
// to keep the review required permission flag per user while an
// install permission's state is shared across all users.
if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
&& bp.isRuntime()) {
return;
}
if (!(uidState.hasPermissionState(permName)
|| pkg.getRequestedPermissions().contains(permName))) {
throw new SecurityException("Package " + pkg.getPackageName()
+ " has not requested permission " + permName);
}
final int flags = uidState.getPermissionFlags(permName);
// Only the system may revoke SYSTEM_FIXED permissions.
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
&& UserHandle.getCallingAppId() != Process.SYSTEM_UID) {
throw new SecurityException("Non-System UID cannot revoke system fixed permission "
+ permName + " for package " + packageName);
}
if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
throw new SecurityException("Cannot revoke policy fixed permission "
+ permName + " for package " + packageName);
}
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
// to keep the review required permission flag per user while an
// install permission's state is shared across all users.
if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime()) {
return;
}
final int flags = uidState.getPermissionFlags(permName);
// Only the system may revoke SYSTEM_FIXED permissions.
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
&& UserHandle.getCallingAppId() != Process.SYSTEM_UID) {
throw new SecurityException("Non-System UID cannot revoke system fixed permission "
+ permName + " for package " + packageName);
}
if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
throw new SecurityException("Cannot revoke policy fixed permission "
+ permName + " for package " + packageName);
}
if (bp.isDevelopment()) {
// Development permissions must be handled specially, since they are not
// 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)) {
if (callback != null) {
mDefaultPermissionCallback.onInstallPermissionRevoked();
}
if (!uidState.revokePermission(bp)) {
return;
}
return;
}
if (!uidState.revokePermission(bp)) {
return;
}
if (bp.isRuntime()) {
@@ -1650,8 +1672,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
if (callback != null) {
callback.onPermissionRevoked(UserHandle.getUid(userId,
UserHandle.getAppId(pkg.getUid())), userId, reason);
if (bp.isDevelopment()) {
mDefaultPermissionCallback.onInstallPermissionRevoked();
} else {
callback.onPermissionRevoked(UserHandle.getUid(userId,
UserHandle.getAppId(pkg.getUid())), userId, reason);
}
}
if (bp.isRuntime()) {
@@ -1686,7 +1712,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @param pkg The package for which to reset.
* @param userId The device user for which to do a reset.
*/
@GuardedBy("mLock")
private void resetRuntimePermissionsInternal(final AndroidPackage pkg,
final int userId) {
final String packageName = pkg.getPackageName();
@@ -2323,7 +2348,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Assume by default that we did not install this permission into the system.
p.setFlags(p.getFlags() & ~PermissionInfo.FLAG_INSTALLED);
synchronized (PermissionManagerService.this.mLock) {
synchronized (mLock) {
// Now that permission groups have a special meaning, we ignore permission
// groups for legacy apps to prevent unexpected behavior. In particular,
// permissions for one app being granted to someone just because they happen
@@ -2463,31 +2488,35 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (ps == null) {
return Collections.emptySet();
}
final UidPermissionState uidState = getUidState(ps, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
return Collections.emptySet();
}
if (!ps.getInstantApp(userId)) {
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.getGrantedPermissions());
instantPermissions.removeIf(permissionName -> {
BasePermission permission = mSettings.getPermission(permissionName);
if (permission == null) {
return true;
}
if (!permission.isInstant()) {
EventLog.writeEvent(0x534e4554, "140256621", UserHandle.getUid(userId,
ps.getAppId()), permissionName);
return true;
}
return false;
});
return instantPermissions;
synchronized (mLock) {
final UidPermissionState uidState = getUidStateLocked(ps, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
return Collections.emptySet();
}
if (!ps.getInstantApp(userId)) {
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.getGrantedPermissions());
instantPermissions.removeIf(permissionName -> {
BasePermission permission = mSettings.getPermission(permissionName);
if (permission == null) {
return true;
}
if (!permission.isInstant()) {
EventLog.writeEvent(0x534e4554, "140256621", UserHandle.getUid(userId,
ps.getAppId()), permissionName);
return true;
}
return false;
});
return instantPermissions;
}
}
}
@@ -3546,13 +3575,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
// Legacy apps have the permission and get user consent on launch.
final UidPermissionState uidState = getUidState(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return false;
synchronized (mLock) {
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return false;
}
return uidState.isPermissionReviewRequired();
}
return uidState.isPermissionReviewRequired();
}
private void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds,
@@ -3565,13 +3596,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void grantRequestedRuntimePermissionsForUser(AndroidPackage pkg, int userId,
String[] grantedPermissions, int callingUid, PermissionCallback callback) {
final UidPermissionState uidState = getUidState(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return;
}
final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
| PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -3593,7 +3617,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
&& (supportsRuntimePermissions || !bp.isRuntimeOnly())
&& (grantedPermissions == null
|| ArrayUtils.contains(grantedPermissions, permission))) {
final int flags = uidState.getPermissionFlags(permission);
final int flags = getPermissionFlagsInternal(permission, pkg.getPackageName(),
callingUid, userId);
if (supportsRuntimePermissions) {
// Installer cannot change immutable permissions.
if ((flags & immutableFlags) == 0) {
@@ -3621,12 +3646,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
for (int i = 0; i < userIds.length; i++) {
int userId = userIds[i];
final UidPermissionState uidState = getUidState(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
continue;
}
for (int j = 0; j < permissionCount; j++) {
final String permissionName = pkg.getRequestedPermissions().get(j);
@@ -3637,14 +3656,26 @@ public class PermissionManagerService extends IPermissionManager.Stub {
continue;
}
if (uidState.isPermissionGranted(permissionName)) {
final boolean isGranted;
synchronized (mLock) {
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
+ " and user " + userId);
continue;
}
isGranted = uidState.isPermissionGranted(permissionName);
}
if (isGranted) {
if (oldGrantedRestrictedPermissions.get(userId) == null) {
oldGrantedRestrictedPermissions.put(userId, new ArraySet<>());
}
oldGrantedRestrictedPermissions.get(userId).add(permissionName);
}
final int oldFlags = uidState.getPermissionFlags(permissionName);
final int oldFlags = getPermissionFlagsInternal(permissionName,
pkg.getPackageName(), callingUid, userId);
int newFlags = oldFlags;
int mask = 0;
@@ -3708,7 +3739,6 @@ 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.isPermissionGranted(permissionName);
if (!isWhitelisted && isGranted) {
mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -3742,15 +3772,19 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int oldGrantedCount = oldPermsForUser.size();
for (int j = 0; j < oldGrantedCount; j++) {
final String permission = oldPermsForUser.valueAt(j);
final String permissionName = oldPermsForUser.valueAt(j);
// Sometimes we create a new permission state instance during update.
final UidPermissionState newUidState = getUidState(pkg, userId);
if (newUidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
+ " and user " + userId);
continue;
final boolean isGranted;
synchronized (mLock) {
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
+ " and user " + userId);
continue;
}
isGranted = uidState.isPermissionGranted(permissionName);
}
if (!newUidState.isPermissionGranted(permission)) {
if (!isGranted) {
callback.onPermissionRevoked(pkg.getUid(), userId, null);
break;
}
@@ -3799,13 +3833,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
continue;
}
UidPermissionState uidState = getUidState(deletedPs.pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + deletedPs.pkg.getPackageName()
+ " and user " + userId);
continue;
}
PackageSetting disabledPs = mPackageManagerInt.getDisabledSystemPackage(
deletedPs.pkg.getPackageName());
@@ -3824,10 +3851,19 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
// 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;
synchronized (mLock) {
UidPermissionState uidState = getUidStateLocked(deletedPs.pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + deletedPs.pkg.getPackageName()
+ " and user " + userId);
continue;
}
// 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;
}
}
}
@@ -4122,14 +4158,17 @@ public class PermissionManagerService extends IPermissionManager.Stub {
} else {
mPackageManagerInt.forEachPackage(p -> {
final int[] userIds = mUserManagerInt.getUserIds();
for (final int userId : userIds) {
final UidPermissionState uidState = getUidState(p, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for "
+ p.getPackageName() + " and user " + userId);
return;
synchronized (mLock) {
for (final int userId : userIds) {
final UidPermissionState uidState = getUidStateLocked(p,
userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for "
+ p.getPackageName() + " and user " + userId);
continue;
}
uidState.removePermissionState(bp.name);
}
uidState.removePermissionState(bp.name);
}
});
}
@@ -4537,26 +4576,24 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Nullable
private UidPermissionState getUidState(@NonNull PackageSetting ps,
private UidPermissionState getUidStateLocked(@NonNull PackageSetting ps,
@UserIdInt int userId) {
return getUidState(ps.getAppId(), userId);
return getUidStateLocked(ps.getAppId(), userId);
}
@Nullable
private UidPermissionState getUidState(@NonNull AndroidPackage pkg,
private UidPermissionState getUidStateLocked(@NonNull AndroidPackage pkg,
@UserIdInt int userId) {
return getUidState(pkg.getUid(), userId);
return getUidStateLocked(pkg.getUid(), userId);
}
@Nullable
private UidPermissionState getUidState(int appId, @UserIdInt int userId) {
synchronized (mLock) {
final UserPermissionState userState = mState.getUserState(userId);
if (userState == null) {
return null;
}
return userState.getUidState(appId);
private UidPermissionState getUidStateLocked(@AppIdInt int appId, @UserIdInt int userId) {
final UserPermissionState userState = mState.getUserState(userId);
if (userState == null) {
return null;
}
return userState.getUidState(appId);
}
private void removeAppIdState(@AppIdInt int appId) {
@@ -4601,7 +4638,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private void writeStateToPackageSettings() {
final int[] userIds = mState.getUserIds();
final int[] userIds;
synchronized (mLock) {
userIds = mState.getUserIds();
}
mPackageManagerInt.forEachPackageSetting(ps -> {
ps.setInstallPermissionsFixed(false);
final LegacyPermissionState legacyState = ps.getLegacyPermissionState();
@@ -4652,27 +4692,30 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@NonNull
private LegacyPermissionState getLegacyPermissionState(@AppIdInt int appId) {
final LegacyPermissionState legacyState = new LegacyPermissionState();
final int[] userIds = mState.getUserIds();
for (final int userId : userIds) {
final UidPermissionState uidState = getUidState(appId, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID "
+ userId);
continue;
}
synchronized (mLock) {
final int[] userIds = mState.getUserIds();
for (final int userId : userIds) {
final UidPermissionState uidState = getUidStateLocked(appId, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID "
+ userId);
continue;
}
final List<PermissionState> permissionStates = uidState.getPermissionStates();
final int permissionStatesSize = permissionStates.size();
for (int i = 0; i < permissionStatesSize; i++) {
final PermissionState permissionState = permissionStates.get(i);
final List<PermissionState> permissionStates = uidState.getPermissionStates();
final int permissionStatesSize = permissionStates.size();
for (int i = 0; i < permissionStatesSize; i++) {
final PermissionState permissionState = permissionStates.get(i);
final LegacyPermissionState.PermissionState legacyPermissionState =
new LegacyPermissionState.PermissionState(permissionState.getPermission(),
permissionState.isGranted(), permissionState.getFlags());
if (permissionState.isRuntime()) {
legacyState.putRuntimePermissionState(legacyPermissionState, userId);
} else if (userId == UserHandle.USER_SYSTEM) {
legacyState.putInstallPermissionState(legacyPermissionState);
final LegacyPermissionState.PermissionState legacyPermissionState =
new LegacyPermissionState.PermissionState(
permissionState.getPermission(), permissionState.isGranted(),
permissionState.getFlags());
if (permissionState.isRuntime()) {
legacyState.putRuntimePermissionState(legacyPermissionState, userId);
} else if (userId == UserHandle.USER_SYSTEM) {
legacyState.putInstallPermissionState(legacyPermissionState);
}
}
}
}
@@ -4683,12 +4726,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private int[] getGidsForUid(int uid) {
final int appId = UserHandle.getAppId(uid);
final int userId = UserHandle.getUserId(uid);
final UidPermissionState uidState = getUidState(appId, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID " + userId);
return EMPTY_INT_ARRAY;
synchronized (mLock) {
final UidPermissionState uidState = getUidStateLocked(appId, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID "
+ userId);
return EMPTY_INT_ARRAY;
}
return uidState.computeGids(mGlobalGids, userId);
}
return uidState.computeGids(mGlobalGids, userId);
}
private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {

View File

@@ -24,8 +24,6 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -35,29 +33,23 @@ import java.util.Set;
* Permission state for a UID.
*/
public final class UidPermissionState {
@NonNull
private final Object mLock = new Object();
private boolean mMissing;
@GuardedBy("mLock")
@Nullable
private ArrayMap<String, PermissionState> mPermissions;
public UidPermissionState() {}
public UidPermissionState(@NonNull UidPermissionState other) {
synchronized (mLock) {
mMissing = other.mMissing;
mMissing = other.mMissing;
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));
}
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));
}
}
}
@@ -66,11 +58,9 @@ public final class UidPermissionState {
* Reset the internal state of this object.
*/
public void reset() {
synchronized (mLock) {
mMissing = false;
mPermissions = null;
invalidateCache();
}
mMissing = false;
mPermissions = null;
invalidateCache();
}
/**
@@ -97,9 +87,7 @@ public final class UidPermissionState {
*/
@Deprecated
public boolean hasPermissionState(@NonNull String name) {
synchronized (mLock) {
return mPermissions != null && mPermissions.containsKey(name);
}
return mPermissions != null && mPermissions.containsKey(name);
}
/**
@@ -109,19 +97,17 @@ public final class UidPermissionState {
*/
@Deprecated
public boolean hasPermissionState(@NonNull ArraySet<String> names) {
synchronized (mLock) {
if (mPermissions == null) {
return false;
}
final int namesSize = names.size();
for (int i = 0; i < namesSize; i++) {
final String name = names.valueAt(i);
if (mPermissions.containsKey(name)) {
return true;
}
}
if (mPermissions == null) {
return false;
}
final int namesSize = names.size();
for (int i = 0; i < namesSize; i++) {
final String name = names.valueAt(i);
if (mPermissions.containsKey(name)) {
return true;
}
}
return false;
}
/**
@@ -132,28 +118,24 @@ public final class UidPermissionState {
*/
@Nullable
public PermissionState getPermissionState(@NonNull String name) {
synchronized (mLock) {
if (mPermissions == null) {
return null;
}
return mPermissions.get(name);
if (mPermissions == null) {
return null;
}
return mPermissions.get(name);
}
@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;
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;
}
/**
@@ -163,12 +145,10 @@ public final class UidPermissionState {
*/
@NonNull
public List<PermissionState> getPermissionStates() {
synchronized (mLock) {
if (mPermissions == null) {
return Collections.emptyList();
}
return new ArrayList<>(mPermissions.values());
if (mPermissions == null) {
return Collections.emptyList();
}
return new ArrayList<>(mPermissions.values());
}
/**
@@ -179,20 +159,18 @@ public final class UidPermissionState {
* @param flags the permission flags
*/
public void putPermissionState(@NonNull BasePermission permission, boolean granted, int flags) {
synchronized (mLock) {
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);
mPermissions.put(name, permissionState);
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);
mPermissions.put(name, permissionState);
}
/**
@@ -202,16 +180,14 @@ public final class UidPermissionState {
* @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;
if (mPermissions == null) {
return false;
}
final boolean changed = mPermissions.remove(name) != null;
if (changed && mPermissions.isEmpty()) {
mPermissions = null;
}
return changed;
}
/**
@@ -232,22 +208,20 @@ public final class UidPermissionState {
*/
@NonNull
public Set<String> getGrantedPermissions() {
synchronized (mLock) {
if (mPermissions == null) {
return Collections.emptySet();
}
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;
if (mPermissions == null) {
return Collections.emptySet();
}
final Set<String> permissions = new ArraySet<>(mPermissions.size());
final int permissionsSize = mPermissions.size();
for (int i = 0; i < permissionsSize; i++) {
final PermissionState permissionState = mPermissions.valueAt(i);
if (permissionState.isGranted()) {
permissions.add(permissionState.getName());
}
}
return permissions;
}
/**
@@ -257,7 +231,7 @@ public final class UidPermissionState {
* @return whether the permission grant state changed
*/
public boolean grantPermission(@NonNull BasePermission permission) {
PermissionState permissionState = getOrCreatePermissionState(permission);
final PermissionState permissionState = getOrCreatePermissionState(permission);
return permissionState.grant();
}
@@ -319,37 +293,33 @@ public final class UidPermissionState {
if (flagMask == 0) {
return false;
}
synchronized (mLock) {
if (mPermissions == null) {
return false;
}
boolean anyChanged = false;
for (int i = mPermissions.size() - 1; i >= 0; i--) {
final PermissionState permissionState = mPermissions.valueAt(i);
final boolean changed = permissionState.updateFlags(flagMask, flagValues);
if (changed && permissionState.isDefault()) {
mPermissions.removeAt(i);
}
anyChanged |= changed;
}
return anyChanged;
if (mPermissions == null) {
return false;
}
boolean anyChanged = false;
for (int i = mPermissions.size() - 1; i >= 0; i--) {
final PermissionState permissionState = mPermissions.valueAt(i);
final boolean changed = permissionState.updateFlags(flagMask, flagValues);
if (changed && permissionState.isDefault()) {
mPermissions.removeAt(i);
}
anyChanged |= changed;
}
return anyChanged;
}
public boolean isPermissionReviewRequired() {
synchronized (mLock) {
if (mPermissions == null) {
return false;
}
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;
}
}
if (mPermissions == null) {
return false;
}
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 false;
}
/**
@@ -360,24 +330,22 @@ public final class UidPermissionState {
*/
@NonNull
public int[] computeGids(@NonNull int[] globalGids, @UserIdInt int userId) {
synchronized (mLock) {
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);
}
}
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();
}
static void invalidateCache() {

View File

@@ -23,8 +23,6 @@ import android.os.UserHandle;
import android.util.ArraySet;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
/**
* Permission state for a user.
*/
@@ -33,71 +31,52 @@ public final class UserPermissionState {
* Whether the install permissions have been granted to a package, so that no install
* permissions should be added to it unless the package is upgraded.
*/
@GuardedBy("mLock")
@NonNull
private final ArraySet<String> mInstallPermissionsFixed = new ArraySet<>();
/**
* Maps from app ID to {@link UidPermissionState}.
*/
@GuardedBy("mLock")
@NonNull
private final SparseArray<UidPermissionState> mUidStates = new SparseArray<>();
@NonNull
private final Object mLock;
public UserPermissionState(@NonNull Object lock) {
mLock = lock;
}
public boolean areInstallPermissionsFixed(@NonNull String packageName) {
synchronized (mLock) {
return mInstallPermissionsFixed.contains(packageName);
}
return mInstallPermissionsFixed.contains(packageName);
}
public void setInstallPermissionsFixed(@NonNull String packageName, boolean fixed) {
synchronized (mLock) {
if (fixed) {
mInstallPermissionsFixed.add(packageName);
} else {
mInstallPermissionsFixed.remove(packageName);
}
if (fixed) {
mInstallPermissionsFixed.add(packageName);
} else {
mInstallPermissionsFixed.remove(packageName);
}
}
@Nullable
public UidPermissionState getUidState(@AppIdInt int appId) {
checkAppId(appId);
synchronized (mLock) {
return mUidStates.get(appId);
}
return mUidStates.get(appId);
}
@NonNull
public UidPermissionState getOrCreateUidState(@AppIdInt int appId) {
checkAppId(appId);
synchronized (mLock) {
UidPermissionState uidState = mUidStates.get(appId);
if (uidState == null) {
uidState = new UidPermissionState();
mUidStates.put(appId, uidState);
}
return uidState;
UidPermissionState uidState = mUidStates.get(appId);
if (uidState == null) {
uidState = new UidPermissionState();
mUidStates.put(appId, uidState);
}
return uidState;
}
public void removeUidState(@AppIdInt int appId) {
checkAppId(appId);
synchronized (mLock) {
mUidStates.delete(appId);
}
mUidStates.delete(appId);
}
private void checkAppId(@AppIdInt int appId) {
if (UserHandle.getUserId(appId) != 0) {
throw new IllegalArgumentException(appId + " is not an app ID");
throw new IllegalArgumentException("Invalid app ID " + appId);
}
}
}