Use the service lock for permission state.
Remove locks inside permission state classes, and make sure that code using mState or calling getUidStateLocked() is under mLock. grantRequestedRuntimePermissionsForUser() and setWhitelistedRestrictedPermissionsForUsers() were never called under the package manager lock, so it's also fine to go through each permission without holding mLock over the entire loop. Bug: 158736025 Test: presubmit Change-Id: I19d7daf76ccdc69bb1494f1b1b45a7e8a05befeb
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user