diff options
| author | 2020-09-14 19:05:44 +0000 | |
|---|---|---|
| committer | 2020-09-14 19:05:44 +0000 | |
| commit | c7eaa75e497de32845ba9c381fdb1b58dfaf1222 (patch) | |
| tree | 4a752b14cc038daaa1e1588db7073a440ac41c73 | |
| parent | 55de2996cb995f8d1e01adfca19a868499e548d5 (diff) | |
| parent | bf519fdd1107f5c3a899ca33639f49334971b4ca (diff) | |
Merge "Revert "Make all permissions per-user.""
10 files changed, 550 insertions, 1469 deletions
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 050c1c4b4df5..ac08d96ab303 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -239,9 +239,7 @@ <!-- Old synonym for "privileged". Deprecated in API level 23. --> <flag name="system" value="0x10" /> <!-- Additional flag from base permission type: this permission can also - (optionally) be granted to development applications. Although undocumented, the - permission state used to be shared by all users (including future users), but it is - managed per-user since API level 31. --> + (optionally) be granted to development applications. --> <flag name="development" value="0x20" /> <!-- Additional flag from base permission type: this permission is closely associated with an app op for controlling access. --> diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 67412a8da7f5..5850dc012226 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1849,7 +1849,7 @@ public class PackageManagerService extends IPackageManager.Stub Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mLock) { removeMessages(WRITE_PACKAGE_LIST); - mPermissionManager.writeStateToPackageSettingsTEMP(); + mPermissionManager.writePermissionsStateToPackageSettingsTEMP(); mSettings.writePackageListLPr(msg.arg1); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); @@ -3520,7 +3520,7 @@ public class PackageManagerService extends IPackageManager.Stub + ((SystemClock.uptimeMillis()-startTime)/1000f) + " seconds"); - mPermissionManager.readStateFromPackageSettingsTEMP(); + mPermissionManager.readPermissionsStateFromPackageSettingsTEMP(); // If the platform SDK has changed since the last time we booted, // we need to re-grant app permission to catch any new ones that // appear. This is really a hack, and means that apps can in some @@ -21827,7 +21827,7 @@ public class PackageManagerService extends IPackageManager.Stub protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return; - mPermissionManager.writeStateToPackageSettingsTEMP(); + mPermissionManager.writePermissionsStateToPackageSettingsTEMP(); DumpState dumpState = new DumpState(); boolean fullPreferred = false; @@ -23707,7 +23707,7 @@ public class PackageManagerService extends IPackageManager.Stub mDirtyUsers.remove(userId); mUserNeedsBadging.delete(userId); mPermissionManager.onUserRemoved(userId); - mPermissionManager.writeStateToPackageSettingsTEMP(); + mPermissionManager.writePermissionsStateToPackageSettingsTEMP(); mSettings.removeUserLPw(userId); mPendingBroadcasts.remove(userId); mInstantAppRegistry.onUserRemovedLPw(userId); @@ -23808,9 +23808,9 @@ public class PackageManagerService extends IPackageManager.Stub boolean readPermissionStateForUser(@UserIdInt int userId) { synchronized (mPackages) { - mPermissionManager.writeStateToPackageSettingsTEMP(); + mPermissionManager.writePermissionsStateToPackageSettingsTEMP(); mSettings.readPermissionStateForUserSyncLPr(userId); - mPermissionManager.readStateFromPackageSettingsTEMP(); + mPermissionManager.readPermissionsStateFromPackageSettingsTEMP(); return mPmInternal.isPermissionUpgradeNeeded(userId); } } @@ -25824,12 +25824,12 @@ public class PackageManagerService extends IPackageManager.Stub /** * Temporary method that wraps mSettings.writeLPr() and calls - * mPermissionManager.writeStateToPackageSettingsTEMP() beforehand. + * mPermissionManager.writePermissionsStateToPackageSettingsTEMP() beforehand. * * TODO(zhanghai): This should be removed once we finish migration of permission storage. */ private void writeSettingsLPrTEMP() { - mPermissionManager.writeStateToPackageSettingsTEMP(); + mPermissionManager.writePermissionsStateToPackageSettingsTEMP(); mSettings.writeLPr(); } } diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java index 865b8a1e97eb..962638b4f63c 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/BasePermission.java @@ -36,7 +36,6 @@ import android.os.UserHandle; import android.util.Log; import android.util.Slog; -import com.android.internal.util.ArrayUtils; import com.android.server.pm.DumpState; import com.android.server.pm.PackageManagerService; import com.android.server.pm.PackageSettingBase; @@ -140,10 +139,6 @@ public final class BasePermission { this.perm = perm; } - public boolean hasGids() { - return !ArrayUtils.isEmpty(gids); - } - public int[] computeGids(int userId) { if (perUser) { final int[] userGids = new int[gids.length]; @@ -424,9 +419,9 @@ public final class BasePermission { } public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg, - UidPermissionState uidState) { + PermissionsState permsState) { int index = pkg.getRequestedPermissions().indexOf(name); - if (!uidState.hasRequestedPermission(name) && index == -1) { + if (!permsState.hasRequestedPermission(name) && index == -1) { throw new SecurityException("Package " + pkg.getPackageName() + " has not requested permission " + name); } diff --git a/services/core/java/com/android/server/pm/permission/DevicePermissionState.java b/services/core/java/com/android/server/pm/permission/DevicePermissionState.java deleted file mode 100644 index b9456acfced5..000000000000 --- a/services/core/java/com/android/server/pm/permission/DevicePermissionState.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.pm.permission; - -import android.annotation.NonNull; -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); - } - } - - @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; - } - } - - public void removeUserState(@UserIdInt int userId) { - synchronized (mLock) { - 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; - } - } -} diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 75e5944b3cb4..1cfc5b135cfa 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -148,9 +148,12 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal.Default import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultDialerProvider; import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultHomeProvider; import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback; +import com.android.server.pm.permission.PermissionsState.PermissionState; import com.android.server.policy.PermissionPolicyInternal; import com.android.server.policy.SoftRestrictedPermissionPolicy; +import libcore.util.EmptyArray; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -223,8 +226,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { /** Internal connection to the user manager */ private final UserManagerInternal mUserManagerInt; - @NonNull - private final DevicePermissionState mState; + /** Maps from App ID to PermissionsState */ + private final SparseArray<PermissionsState> mAppIdStates = new SparseArray<>(); /** Permission controller: User space permission management */ private PermissionControllerManager mPermissionControllerManager; @@ -392,7 +395,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, @@ -679,12 +681,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { 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); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + packageName); return 0; } - return uidState.getPermissionFlags(permName); + return permissionsState.getPermissionFlags(permName, userId); } @Override @@ -786,13 +788,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown permission: " + permName); } - final UidPermissionState uidState = getUidState(pkg, userId); - if (uidState == null) { - Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + packageName); return; } - final boolean hadState = uidState.getPermissionState(permName) != null; + final boolean hadState = + permissionsState.getRuntimePermissionState(permName, userId) != null; if (!hadState) { boolean isRequested = false; // Fast path, the current package has requested the permission. @@ -819,18 +822,20 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } final boolean permissionUpdated = - uidState.updatePermissionFlags(bp, flagMask, flagValues); + permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues); if (permissionUpdated && bp.isRuntime()) { notifyRuntimePermissionStateChanged(packageName, userId); } if (permissionUpdated && callback != null) { // Install and runtime permissions are stored in different places, // so figure out what permission changed and persist the change. - if (!bp.isRuntime()) { + if (permissionsState.getInstallPermissionState(permName) != null) { int userUid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid())); callback.onInstallPermissionUpdatedNotifyListener(userUid); - } else { - callback.onPermissionUpdatedNotifyListener(new int[]{userId}, false, pkg.getUid()); + } else if (permissionsState.getRuntimePermissionState(permName, userId) != null + || hadState) { + callback.onPermissionUpdatedNotifyListener(new int[]{userId}, false, + pkg.getUid()); } } } @@ -863,14 +868,13 @@ 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); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return; } - changed[0] |= uidState.updatePermissionFlagsForAllPermissions( - effectiveFlagMask, effectiveFlagValues); + changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions( + userId, effectiveFlagMask, effectiveFlagValues); mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid()); }); @@ -922,20 +926,19 @@ 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); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return PackageManager.PERMISSION_DENIED; } - if (checkSinglePermissionInternal(uid, uidState, permissionName)) { + if (checkSinglePermissionInternal(uid, permissionsState, permissionName)) { return PackageManager.PERMISSION_GRANTED; } final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName); if (fullerPermissionName != null - && checkSinglePermissionInternal(uid, uidState, fullerPermissionName)) { + && checkSinglePermissionInternal(uid, permissionsState, fullerPermissionName)) { return PackageManager.PERMISSION_GRANTED; } @@ -943,8 +946,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { } private boolean checkSinglePermissionInternal(int uid, - @NonNull UidPermissionState uidState, @NonNull String permissionName) { - if (!uidState.hasPermission(permissionName)) { + @NonNull PermissionsState permissionsState, @NonNull String permissionName) { + if (!permissionsState.hasPermission(permissionName, UserHandle.getUserId(uid))) { return false; } @@ -1138,9 +1141,9 @@ 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); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + packageName); return null; } @@ -1161,7 +1164,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int i = 0; i < permissionCount; i++) { final String permissionName = pkg.getRequestedPermissions().get(i); final int currentFlags = - uidState.getPermissionFlags(permissionName); + permissionsState.getPermissionFlags(permissionName, userId); if ((currentFlags & queryFlags) != 0) { if (whitelistedPermissions == null) { whitelistedPermissions = new ArrayList<>(); @@ -1450,14 +1453,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { 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); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return; } - bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, uidState); + bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState); // If a permission review is required for legacy apps we represent // their permissions as always granted runtime ones since we need @@ -1470,7 +1472,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid())); - final int flags = uidState.getPermissionFlags(permName); + final int flags = permissionsState.getPermissionFlags(permName, userId); if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) { Log.e(TAG, "Cannot grant system fixed permission " + permName + " for package " + packageName); @@ -1500,9 +1502,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { 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) != PERMISSION_OPERATION_FAILURE) { + if (permissionsState.grantInstallPermission(bp) + != PERMISSION_OPERATION_FAILURE) { if (callback != null) { callback.onInstallPermissionGranted(); } @@ -1520,7 +1521,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return; } - final int result = uidState.grantPermission(bp); + final int result = permissionsState.grantRuntimePermission(bp, userId); switch (result) { case PERMISSION_OPERATION_FAILURE: { return; @@ -1616,14 +1617,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { 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); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return; } - bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, uidState); + bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState); // If a permission review is required for legacy apps we represent // their permissions as always granted runtime ones since we need @@ -1634,7 +1634,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return; } - final int flags = uidState.getPermissionFlags(permName); + final int flags = permissionsState.getPermissionFlags(permName, userId); // Only the system may revoke SYSTEM_FIXED permissions. if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0 && UserHandle.getCallingAppId() != Process.SYSTEM_UID) { @@ -1649,9 +1649,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { 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) != PERMISSION_OPERATION_FAILURE) { + if (permissionsState.revokeInstallPermission(bp) + != PERMISSION_OPERATION_FAILURE) { if (callback != null) { mDefaultPermissionCallback.onInstallPermissionRevoked(); } @@ -1660,11 +1659,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { } // Permission is already revoked, no need to do anything. - if (!uidState.hasPermission(permName)) { + if (!permissionsState.hasRuntimePermission(permName, userId)) { return; } - if (uidState.revokePermission(bp) == PERMISSION_OPERATION_FAILURE) { + if (permissionsState.revokeRuntimePermission(bp, userId) + == PERMISSION_OPERATION_FAILURE) { return; } @@ -2466,7 +2466,19 @@ public class PermissionManagerService extends IPermissionManager.Stub { private void onUserRemoved(@UserIdInt int userId) { synchronized (mLock) { - mState.removeUserState(userId); + final int appIdStatesSize = mAppIdStates.size(); + for (int i = 0; i < appIdStatesSize; i++) { + PermissionsState permissionsState = mAppIdStates.valueAt(i); + for (PermissionState permissionState + : permissionsState.getRuntimePermissionStates(userId)) { + BasePermission bp = mSettings.getPermission(permissionState.getName()); + if (bp != null) { + permissionsState.revokeRuntimePermission(bp, userId); + permissionsState.updatePermissionFlags(bp, userId, + PackageManager.MASK_PERMISSION_FLAGS_ALL, 0); + } + } + } } } @@ -2477,18 +2489,19 @@ 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); + final PermissionsState permissionsState = getPermissionsState(ps); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + packageName); return Collections.emptySet(); } if (!ps.getInstantApp(userId)) { - return uidState.getPermissions(); + return permissionsState.getPermissions(userId); } else { // Install permission state is shared among all users, but instant app state is // per-user, so we can only filter it here unless we make install permission state // per-user as well. - final Set<String> instantPermissions = new ArraySet<>(uidState.getPermissions()); + final Set<String> instantPermissions = new ArraySet<>(permissionsState.getPermissions( + userId)); instantPermissions.removeIf(permissionName -> { BasePermission permission = mSettings.getPermission(permissionName); if (permission == null) { @@ -2520,12 +2533,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (ps == null) { return null; } - final UidPermissionState uidState = getUidState(ps, userId); - if (uidState == null) { - Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId); + final PermissionsState permissionsState = getPermissionsState(ps); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + packageName); return null; } - return uidState.computeGids(userId); + return permissionsState.computeGids(userId); } /** @@ -2562,17 +2575,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (ps == null) { return; } + final PermissionsState permissionsState = getOrCreatePermissionsState(ps); final int[] userIds = getAllUserIds(); boolean runtimePermissionsRevoked = false; int[] updatedUserIds = EMPTY_INT_ARRAY; - for (final int userId : userIds) { - final UserPermissionState userState = mState.getOrCreateUserState(userId); - final UidPermissionState uidState = userState.getOrCreateUidState(ps.getAppId()); - - if (uidState.isMissing()) { + for (int userId : userIds) { + if (permissionsState.isMissing(userId)) { Collection<String> requestedPermissions; int targetSdkVersion; if (!ps.isSharedUser()) { @@ -2600,220 +2611,222 @@ public class PermissionManagerService extends IPermissionManager.Stub { && permission.isRuntime() && !permission.isRemoved()) { if (permission.isHardOrSoftRestricted() || permission.isImmutablyRestricted()) { - uidState.updatePermissionFlags(permission, + permissionsState.updatePermissionFlags(permission, userId, FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT); } if (targetSdkVersion < Build.VERSION_CODES.M) { - uidState.updatePermissionFlags(permission, + permissionsState.updatePermissionFlags(permission, userId, PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT); - uidState.grantPermission(permission); + permissionsState.grantRuntimePermission(permission, userId); } } } - uidState.setMissing(false); + permissionsState.setMissing(false, userId); updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); } + } - UidPermissionState origState = uidState; + PermissionsState origPermissions = permissionsState; - boolean changedInstallPermission = false; + boolean changedInstallPermission = false; - if (replace) { - userState.setInstallPermissionsFixed(ps.name, false); - if (!ps.isSharedUser()) { - origState = new UidPermissionState(uidState); - uidState.reset(); - } else { - // We need to know only about runtime permission changes since the - // calling code always writes the install permissions state but - // the runtime ones are written only if changed. The only cases of - // changed runtime permissions here are promotion of an install to - // runtime and revocation of a runtime from a shared user. - synchronized (mLock) { - if (revokeUnusedSharedUserPermissionsLocked( - ps.getSharedUser().getPackages(), uidState)) { - updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); - runtimePermissionsRevoked = true; - } + if (replace) { + ps.setInstallPermissionsFixed(false); + if (!ps.isSharedUser()) { + origPermissions = new PermissionsState(permissionsState); + permissionsState.reset(); + } else { + // We need to know only about runtime permission changes since the + // calling code always writes the install permissions state but + // the runtime ones are written only if changed. The only cases of + // changed runtime permissions here are promotion of an install to + // runtime and revocation of a runtime from a shared user. + synchronized (mLock) { + updatedUserIds = revokeUnusedSharedUserPermissionsLocked( + ps.getSharedUser().getPackages(), permissionsState, userIds); + if (!ArrayUtils.isEmpty(updatedUserIds)) { + runtimePermissionsRevoked = true; } } } + } - uidState.setGlobalGids(mGlobalGids); + permissionsState.setGlobalGids(mGlobalGids); - ArraySet<String> newImplicitPermissions = new ArraySet<>(); + ArraySet<String> newImplicitPermissions = new ArraySet<>(); - final int N = pkg.getRequestedPermissions().size(); - for (int i = 0; i < N; i++) { - final String permName = pkg.getRequestedPermissions().get(i); - final BasePermission bp = mSettings.getPermission(permName); - final boolean appSupportsRuntimePermissions = - pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; - String upgradedActivityRecognitionPermission = null; + final int N = pkg.getRequestedPermissions().size(); + for (int i = 0; i < N; i++) { + final String permName = pkg.getRequestedPermissions().get(i); + final BasePermission bp = mSettings.getPermission(permName); + final boolean appSupportsRuntimePermissions = + pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; + String upgradedActivityRecognitionPermission = null; - if (DEBUG_INSTALL && bp != null) { - Log.i(TAG, "Package " + pkg.getPackageName() - + " checking " + permName + ": " + bp); - } + if (DEBUG_INSTALL && bp != null) { + Log.i(TAG, "Package " + pkg.getPackageName() + + " checking " + permName + ": " + bp); + } - if (bp == null || getSourcePackageSetting(bp) == null) { - if (packageOfInterest == null || packageOfInterest.equals( - pkg.getPackageName())) { - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, "Unknown permission " + permName - + " in package " + pkg.getPackageName()); - } + if (bp == null || getSourcePackageSetting(bp) == null) { + if (packageOfInterest == null || packageOfInterest.equals( + pkg.getPackageName())) { + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, "Unknown permission " + permName + + " in package " + pkg.getPackageName()); } - continue; } + continue; + } - // Cache newImplicitPermissions before modifing permissionsState as for the shared - // uids the original and new state are the same object - if (!origState.hasRequestedPermission(permName) - && (pkg.getImplicitPermissions().contains(permName) - || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) { - if (pkg.getImplicitPermissions().contains(permName)) { - // If permName is an implicit permission, try to auto-grant - newImplicitPermissions.add(permName); + // Cache newImplicitPermissions before modifing permissionsState as for the shared + // uids the original and new state are the same object + if (!origPermissions.hasRequestedPermission(permName) + && (pkg.getImplicitPermissions().contains(permName) + || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) { + if (pkg.getImplicitPermissions().contains(permName)) { + // If permName is an implicit permission, try to auto-grant + newImplicitPermissions.add(permName); - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName()); - } - } else { - // Special case for Activity Recognition permission. Even if AR permission - // is not an implicit permission we want to add it to the list (try to - // auto-grant it) if the app was installed on a device before AR permission - // was split, regardless of if the app now requests the new AR permission - // or has updated its target SDK and AR is no longer implicit to it. - // This is a compatibility workaround for apps when AR permission was - // split in Q. - final List<SplitPermissionInfoParcelable> permissionList = - getSplitPermissions(); - int numSplitPerms = permissionList.size(); - for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) { - SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum); - String splitPermName = sp.getSplitPermission(); - if (sp.getNewPermissions().contains(permName) - && origState.hasInstallPermission(splitPermName)) { - upgradedActivityRecognitionPermission = splitPermName; - newImplicitPermissions.add(permName); + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName()); + } + } else { + // Special case for Activity Recognition permission. Even if AR permission + // is not an implicit permission we want to add it to the list (try to + // auto-grant it) if the app was installed on a device before AR permission + // was split, regardless of if the app now requests the new AR permission + // or has updated its target SDK and AR is no longer implicit to it. + // This is a compatibility workaround for apps when AR permission was + // split in Q. + final List<SplitPermissionInfoParcelable> permissionList = + getSplitPermissions(); + int numSplitPerms = permissionList.size(); + for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) { + SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum); + String splitPermName = sp.getSplitPermission(); + if (sp.getNewPermissions().contains(permName) + && origPermissions.hasInstallPermission(splitPermName)) { + upgradedActivityRecognitionPermission = splitPermName; + newImplicitPermissions.add(permName); - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, permName + " is newly added for " - + pkg.getPackageName()); - } - break; + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, permName + " is newly added for " + + pkg.getPackageName()); } + break; } } } + } - // TODO(b/140256621): The package instant app method has been removed - // as part of work in b/135203078, so this has been commented out in the meantime - // Limit ephemeral apps to ephemeral allowed permissions. - // if (/*pkg.isInstantApp()*/ false && !bp.isInstant()) { - // if (DEBUG_PERMISSIONS) { - // Log.i(TAG, "Denying non-ephemeral permission " + bp.getName() - // + " for package " + pkg.getPackageName()); - // } - // continue; - // } - - if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) { - if (DEBUG_PERMISSIONS) { - Log.i(TAG, "Denying runtime-only permission " + bp.getName() - + " for package " + pkg.getPackageName()); - } - continue; + // TODO(b/140256621): The package instant app method has been removed + // as part of work in b/135203078, so this has been commented out in the meantime + // Limit ephemeral apps to ephemeral allowed permissions. +// if (/*pkg.isInstantApp()*/ false && !bp.isInstant()) { +// if (DEBUG_PERMISSIONS) { +// Log.i(TAG, "Denying non-ephemeral permission " + bp.getName() +// + " for package " + pkg.getPackageName()); +// } +// continue; +// } + + if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) { + if (DEBUG_PERMISSIONS) { + Log.i(TAG, "Denying runtime-only permission " + bp.getName() + + " for package " + pkg.getPackageName()); } + continue; + } - final String perm = bp.getName(); - boolean allowedSig = false; - int grant = GRANT_DENIED; + final String perm = bp.getName(); + boolean allowedSig = false; + int grant = GRANT_DENIED; - // Keep track of app op permissions. - if (bp.isAppOp()) { - mSettings.addAppOpPackage(perm, pkg.getPackageName()); - } + // Keep track of app op permissions. + if (bp.isAppOp()) { + mSettings.addAppOpPackage(perm, pkg.getPackageName()); + } - if (bp.isNormal()) { - // For all apps normal permissions are install time ones. + if (bp.isNormal()) { + // For all apps normal permissions are install time ones. + grant = GRANT_INSTALL; + } else if (bp.isRuntime()) { + if (origPermissions.hasInstallPermission(bp.getName()) + || upgradedActivityRecognitionPermission != null) { + // Before Q we represented some runtime permissions as install permissions, + // in Q we cannot do this anymore. Hence upgrade them all. + grant = GRANT_UPGRADE; + } else { + // For modern apps keep runtime permissions unchanged. + grant = GRANT_RUNTIME; + } + } else if (bp.isSignature()) { + // For all apps signature permissions are install time ones. + allowedSig = shouldGrantSignaturePermission(perm, pkg, ps, bp, origPermissions); + if (allowedSig) { grant = GRANT_INSTALL; - } else if (bp.isRuntime()) { - if (origState.hasInstallPermission(bp.getName()) - || upgradedActivityRecognitionPermission != null) { - // Before Q we represented some runtime permissions as install permissions, - // in Q we cannot do this anymore. Hence upgrade them all. - grant = GRANT_UPGRADE; - } else { - // For modern apps keep runtime permissions unchanged. - grant = GRANT_RUNTIME; - } - } else if (bp.isSignature()) { - // For all apps signature permissions are install time ones. - allowedSig = shouldGrantSignaturePermission(perm, pkg, ps, bp, origState); - if (allowedSig) { - grant = GRANT_INSTALL; - } } + } - if (grant != GRANT_DENIED) { - if (!ps.isSystem() && userState.areInstallPermissionsFixed(ps.name) - && !bp.isRuntime()) { - // If this is an existing, non-system package, then - // we can't add any new permissions to it. Runtime - // permissions can be added any time - they ad dynamic. - if (!allowedSig && !origState.hasInstallPermission(perm)) { - // Except... if this is a permission that was added - // to the platform (note: need to only do this when - // updating the platform). - if (!isNewPlatformPermissionForPackage(perm, pkg)) { - grant = GRANT_DENIED; - } + if (grant != GRANT_DENIED) { + if (!ps.isSystem() && ps.areInstallPermissionsFixed() && !bp.isRuntime()) { + // If this is an existing, non-system package, then + // we can't add any new permissions to it. Runtime + // permissions can be added any time - they ad dynamic. + if (!allowedSig && !origPermissions.hasInstallPermission(perm)) { + // Except... if this is a permission that was added + // to the platform (note: need to only do this when + // updating the platform). + if (!isNewPlatformPermissionForPackage(perm, pkg)) { + grant = GRANT_DENIED; } } } + } - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, "Considering granting permission " + perm + " to package " - + pkg.getPackageName()); - } + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, "Considering granting permission " + perm + " to package " + + pkg.getPackageName()); + } - synchronized (mLock) { - if (grant != GRANT_DENIED) { - switch (grant) { - case GRANT_INSTALL: { - // Revoke this as runtime permission to handle the case of - // a runtime permission being downgraded to an install one. - // Also in permission review mode we keep dangerous permissions - // for legacy apps - final PermissionState origPermissionState = - origState.getPermissionState(perm); - if (origPermissionState != null - && origPermissionState.isRuntime()) { + synchronized (mLock) { + if (grant != GRANT_DENIED) { + switch (grant) { + case GRANT_INSTALL: { + // Revoke this as runtime permission to handle the case of + // a runtime permission being downgraded to an install one. + // Also in permission review mode we keep dangerous permissions + // for legacy apps + for (int userId : userIds) { + if (origPermissions.getRuntimePermissionState( + perm, userId) != null) { // Revoke the runtime permission and clear the flags. - origState.revokePermission(bp); - origState.updatePermissionFlags(bp, + origPermissions.revokeRuntimePermission(bp, userId); + origPermissions.updatePermissionFlags(bp, userId, PackageManager.MASK_PERMISSION_FLAGS_ALL, 0); // If we revoked a permission permission, we have to write. updatedUserIds = ArrayUtils.appendInt( updatedUserIds, userId); } - // Grant an install permission. - if (uidState.grantPermission(bp) != PERMISSION_OPERATION_FAILURE) { - changedInstallPermission = true; - } - } break; + } + // Grant an install permission. + if (permissionsState.grantInstallPermission(bp) != + PERMISSION_OPERATION_FAILURE) { + changedInstallPermission = true; + } + } break; - case GRANT_RUNTIME: { - boolean hardRestricted = bp.isHardRestricted(); - boolean softRestricted = bp.isSoftRestricted(); + case GRANT_RUNTIME: { + boolean hardRestricted = bp.isHardRestricted(); + boolean softRestricted = bp.isSoftRestricted(); + for (int userId : userIds) { // If permission policy is not ready we don't deal with restricted // permissions as the policy may whitelist some permissions. Once // the policy is initialized we would re-evaluate permissions. @@ -2821,24 +2834,25 @@ public class PermissionManagerService extends IPermissionManager.Stub { mPermissionPolicyInternal != null && mPermissionPolicyInternal.isInitialized(userId); - PermissionState origPermState = origState.getPermissionState(perm); - int flags = origPermState != null ? origPermState.getFlags() : 0; + PermissionState permState = origPermissions + .getRuntimePermissionState(perm, userId); + int flags = permState != null ? permState.getFlags() : 0; boolean wasChanged = false; boolean restrictionExempt = - (origState.getPermissionFlags(bp.name) + (origPermissions.getPermissionFlags(bp.name, userId) & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0; - boolean restrictionApplied = (origState.getPermissionFlags( - bp.name) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; + boolean restrictionApplied = (origPermissions.getPermissionFlags( + bp.name, userId) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; if (appSupportsRuntimePermissions) { // If hard restricted we don't allow holding it if (permissionPolicyInitialized && hardRestricted) { if (!restrictionExempt) { - if (origPermState != null && origPermState.isGranted() - && uidState.revokePermission( - bp) != PERMISSION_OPERATION_FAILURE) { + if (permState != null && permState.isGranted() + && permissionsState.revokeRuntimePermission( + bp, userId) != PERMISSION_OPERATION_FAILURE) { wasChanged = true; } if (!restrictionApplied) { @@ -2868,15 +2882,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Hard restricted permissions cannot be held. } else if (!permissionPolicyInitialized || (!hardRestricted || restrictionExempt)) { - if (origPermState != null && origPermState.isGranted()) { - if (uidState.grantPermission(bp) + if (permState != null && permState.isGranted()) { + if (permissionsState.grantRuntimePermission(bp, userId) == PERMISSION_OPERATION_FAILURE) { wasChanged = true; } } } } else { - if (origPermState == null) { + if (permState == null) { // New permission if (PLATFORM_PACKAGE_NAME.equals( bp.getSourcePackageName())) { @@ -2888,8 +2902,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - if (!uidState.hasPermission(bp.name) - && uidState.grantPermission(bp) + if (!permissionsState.hasRuntimePermission(bp.name, userId) + && permissionsState.grantRuntimePermission(bp, userId) != PERMISSION_OPERATION_FAILURE) { wasChanged = true; } @@ -2922,32 +2936,36 @@ public class PermissionManagerService extends IPermissionManager.Stub { updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); } - uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL, - flags); - } break; - - case GRANT_UPGRADE: { - // Upgrade from Pre-Q to Q permission model. Make all permissions - // runtime - PermissionState origPermState = origState.getPermissionState(perm); - int flags = (origPermState != null) ? origPermState.getFlags() : 0; - - BasePermission bpToRevoke = - upgradedActivityRecognitionPermission == null - ? bp : mSettings.getPermissionLocked( - upgradedActivityRecognitionPermission); - // Remove install permission - if (origState.revokePermission(bpToRevoke) - != PERMISSION_OPERATION_FAILURE) { - origState.updatePermissionFlags(bpToRevoke, - (MASK_PERMISSION_FLAGS_ALL - & ~FLAG_PERMISSION_APPLY_RESTRICTION), 0); - changedInstallPermission = true; - } + permissionsState.updatePermissionFlags(bp, userId, + MASK_PERMISSION_FLAGS_ALL, flags); + } + } break; + + case GRANT_UPGRADE: { + // Upgrade from Pre-Q to Q permission model. Make all permissions + // runtime + PermissionState permState = origPermissions + .getInstallPermissionState(perm); + int flags = (permState != null) ? permState.getFlags() : 0; + + BasePermission bpToRevoke = + upgradedActivityRecognitionPermission == null + ? bp : mSettings.getPermissionLocked( + upgradedActivityRecognitionPermission); + // Remove install permission + if (origPermissions.revokeInstallPermission(bpToRevoke) + != PERMISSION_OPERATION_FAILURE) { + origPermissions.updatePermissionFlags(bpToRevoke, + UserHandle.USER_ALL, + (MASK_PERMISSION_FLAGS_ALL + & ~FLAG_PERMISSION_APPLY_RESTRICTION), 0); + changedInstallPermission = true; + } - boolean hardRestricted = bp.isHardRestricted(); - boolean softRestricted = bp.isSoftRestricted(); + boolean hardRestricted = bp.isHardRestricted(); + boolean softRestricted = bp.isSoftRestricted(); + for (int userId : userIds) { // If permission policy is not ready we don't deal with restricted // permissions as the policy may whitelist some permissions. Once // the policy is initialized we would re-evaluate permissions. @@ -2958,18 +2976,18 @@ public class PermissionManagerService extends IPermissionManager.Stub { boolean wasChanged = false; boolean restrictionExempt = - (origState.getPermissionFlags(bp.name) + (origPermissions.getPermissionFlags(bp.name, userId) & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0; - boolean restrictionApplied = (origState.getPermissionFlags( - bp.name) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; + boolean restrictionApplied = (origPermissions.getPermissionFlags( + bp.name, userId) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; if (appSupportsRuntimePermissions) { // If hard restricted we don't allow holding it if (permissionPolicyInitialized && hardRestricted) { if (!restrictionExempt) { - if (origPermState != null && origPermState.isGranted() - && uidState.revokePermission( - bp) != PERMISSION_OPERATION_FAILURE) { + if (permState != null && permState.isGranted() + && permissionsState.revokeRuntimePermission( + bp, userId) != PERMISSION_OPERATION_FAILURE) { wasChanged = true; } if (!restrictionApplied) { @@ -2999,15 +3017,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Hard restricted permissions cannot be held. } else if (!permissionPolicyInitialized || (!hardRestricted || restrictionExempt)) { - if (uidState.grantPermission(bp) - != PERMISSION_OPERATION_FAILURE) { + if (permissionsState.grantRuntimePermission(bp, userId) != + PERMISSION_OPERATION_FAILURE) { wasChanged = true; } } } else { - if (!uidState.hasPermission(bp.name) - && uidState.grantPermission(bp) - != PERMISSION_OPERATION_FAILURE) { + if (!permissionsState.hasRuntimePermission(bp.name, userId) + && permissionsState.grantRuntimePermission(bp, + userId) != PERMISSION_OPERATION_FAILURE) { flags |= FLAG_PERMISSION_REVIEW_REQUIRED; wasChanged = true; } @@ -3040,74 +3058,71 @@ public class PermissionManagerService extends IPermissionManager.Stub { updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); } - uidState.updatePermissionFlags(bp, + permissionsState.updatePermissionFlags(bp, userId, MASK_PERMISSION_FLAGS_ALL, flags); - } break; + } + } break; - default: { - if (packageOfInterest == null - || packageOfInterest.equals(pkg.getPackageName())) { - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, "Not granting permission " + perm - + " to package " + pkg.getPackageName() - + " because it was previously installed without"); - } + default: { + if (packageOfInterest == null + || packageOfInterest.equals(pkg.getPackageName())) { + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, "Not granting permission " + perm + + " to package " + pkg.getPackageName() + + " because it was previously installed without"); } - } break; - } - } else { - if (uidState.revokePermission(bp) != PERMISSION_OPERATION_FAILURE) { - // Also drop the permission flags. - uidState.updatePermissionFlags(bp, - MASK_PERMISSION_FLAGS_ALL, 0); - changedInstallPermission = true; - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, "Un-granting permission " + perm - + " from package " + pkg.getPackageName() - + " (protectionLevel=" + bp.getProtectionLevel() - + " flags=0x" - + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, - ps)) - + ")"); - } - } else if (bp.isAppOp()) { - // Don't print warning for app op permissions, since it is fine for them - // not to be granted, there is a UI for the user to decide. - if (DEBUG_PERMISSIONS - && (packageOfInterest == null - || packageOfInterest.equals(pkg.getPackageName()))) { - Slog.i(TAG, "Not granting permission " + perm - + " to package " + pkg.getPackageName() - + " (protectionLevel=" + bp.getProtectionLevel() - + " flags=0x" - + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, - ps)) - + ")"); } + } break; + } + } else { + if (permissionsState.revokeInstallPermission(bp) != + PERMISSION_OPERATION_FAILURE) { + // Also drop the permission flags. + permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, + MASK_PERMISSION_FLAGS_ALL, 0); + changedInstallPermission = true; + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, "Un-granting permission " + perm + + " from package " + pkg.getPackageName() + + " (protectionLevel=" + bp.getProtectionLevel() + + " flags=0x" + + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, ps)) + + ")"); + } + } else if (bp.isAppOp()) { + // Don't print warning for app op permissions, since it is fine for them + // not to be granted, there is a UI for the user to decide. + if (DEBUG_PERMISSIONS + && (packageOfInterest == null + || packageOfInterest.equals(pkg.getPackageName()))) { + Slog.i(TAG, "Not granting permission " + perm + + " to package " + pkg.getPackageName() + + " (protectionLevel=" + bp.getProtectionLevel() + + " flags=0x" + + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, ps)) + + ")"); } } } } + } - if ((changedInstallPermission || replace) - && !userState.areInstallPermissionsFixed(ps.name) - && !ps.isSystem() || ps.getPkgState().isUpdatedSystemApp()) { - // This is the first that we have heard about this package, so the - // permissions we have now selected are fixed until explicitly - // changed. - userState.setInstallPermissionsFixed(ps.name, true); - } - - synchronized (mLock) { - updatedUserIds = revokePermissionsNoLongerImplicitLocked(uidState, pkg, - userId, updatedUserIds); - updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origState, - uidState, pkg, newImplicitPermissions, userId, updatedUserIds); - } + if ((changedInstallPermission || replace) && !ps.areInstallPermissionsFixed() && + !ps.isSystem() || ps.getPkgState().isUpdatedSystemApp()) { + // This is the first that we have heard about this package, so the + // permissions we have now selected are fixed until explicitly + // changed. + ps.setInstallPermissionsFixed(true); } - updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, userIds, - updatedUserIds); + synchronized (mLock) { + updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg, + userIds, updatedUserIds); + updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions, + permissionsState, pkg, newImplicitPermissions, userIds, updatedUserIds); + updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, userIds, + updatedUserIds); + } // TODO: Kill UIDs whose GIDs or runtime permissions changed. This might be more important // for shared users. @@ -3144,38 +3159,40 @@ public class PermissionManagerService extends IPermissionManager.Stub { * * @return The updated value of the {@code updatedUserIds} parameter */ - private @NonNull int[] revokePermissionsNoLongerImplicitLocked(@NonNull UidPermissionState ps, - @NonNull AndroidPackage pkg, int userId, @NonNull int[] updatedUserIds) { + private @NonNull int[] revokePermissionsNoLongerImplicitLocked(@NonNull PermissionsState ps, + @NonNull AndroidPackage pkg, @NonNull int[] userIds, @NonNull int[] updatedUserIds) { String pkgName = pkg.getPackageName(); boolean supportsRuntimePermissions = pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; - for (String permission : ps.getPermissions()) { - if (!pkg.getImplicitPermissions().contains(permission)) { - if (!ps.hasInstallPermission(permission)) { - int flags = ps.getPermissionFlags(permission); + for (int userId : userIds) { + for (String permission : ps.getPermissions(userId)) { + if (!pkg.getImplicitPermissions().contains(permission)) { + if (!ps.hasInstallPermission(permission)) { + int flags = ps.getRuntimePermissionState(permission, userId).getFlags(); - if ((flags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) { - BasePermission bp = mSettings.getPermissionLocked(permission); + if ((flags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) { + BasePermission bp = mSettings.getPermissionLocked(permission); - int flagsToRemove = FLAG_PERMISSION_REVOKE_WHEN_REQUESTED; + int flagsToRemove = FLAG_PERMISSION_REVOKE_WHEN_REQUESTED; - if ((flags & BLOCKING_PERMISSION_FLAGS) == 0 - && supportsRuntimePermissions) { - int revokeResult = ps.revokePermission(bp); - if (revokeResult != PERMISSION_OPERATION_FAILURE) { - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, "Revoking runtime permission " - + permission + " for " + pkgName - + " as it is now requested"); + if ((flags & BLOCKING_PERMISSION_FLAGS) == 0 + && supportsRuntimePermissions) { + int revokeResult = ps.revokeRuntimePermission(bp, userId); + if (revokeResult != PERMISSION_OPERATION_FAILURE) { + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, "Revoking runtime permission " + + permission + " for " + pkgName + + " as it is now requested"); + } } + + flagsToRemove |= USER_PERMISSION_FLAGS; } - flagsToRemove |= USER_PERMISSION_FLAGS; + ps.updatePermissionFlags(bp, userId, flagsToRemove, 0); + updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); } - - ps.updatePermissionFlags(bp, flagsToRemove, 0); - updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); } } } @@ -3196,10 +3213,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param newPerm The permission to inherit to * @param ps The permission state of the package * @param pkg The package requesting the permissions + * @param userId The user the permission belongs to */ private void inheritPermissionStateToNewImplicitPermissionLocked( @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm, - @NonNull UidPermissionState ps, @NonNull AndroidPackage pkg) { + @NonNull PermissionsState ps, @NonNull AndroidPackage pkg, + @UserIdInt int userId) { String pkgName = pkg.getPackageName(); boolean isGranted = false; int flags = 0; @@ -3207,16 +3226,17 @@ public class PermissionManagerService extends IPermissionManager.Stub { int numSourcePerm = sourcePerms.size(); for (int i = 0; i < numSourcePerm; i++) { String sourcePerm = sourcePerms.valueAt(i); - if (ps.hasPermission(sourcePerm)) { + if ((ps.hasRuntimePermission(sourcePerm, userId)) + || ps.hasInstallPermission(sourcePerm)) { if (!isGranted) { flags = 0; } isGranted = true; - flags |= ps.getPermissionFlags(sourcePerm); + flags |= ps.getPermissionFlags(sourcePerm, userId); } else { if (!isGranted) { - flags |= ps.getPermissionFlags(sourcePerm); + flags |= ps.getPermissionFlags(sourcePerm, userId); } } } @@ -3227,11 +3247,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { + " for " + pkgName); } - ps.grantPermission(mSettings.getPermissionLocked(newPerm)); + ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId); } // Add permission flags - ps.updatePermissionFlags(mSettings.getPermission(newPerm), flags, flags); + ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags, flags); } /** @@ -3263,15 +3283,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param origPs The permission state of the package before the split * @param ps The new permission state * @param pkg The package the permission belongs to - * @param userId The user ID + * @param userIds All user IDs in the system, must be passed in because this method is locked * @param updatedUserIds List of users for which the permission state has already been changed * * @return List of users for which the permission state has been changed */ private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked( - @NonNull UidPermissionState origPs, @NonNull UidPermissionState ps, + @NonNull PermissionsState origPs, @NonNull PermissionsState ps, @NonNull AndroidPackage pkg, @NonNull ArraySet<String> newImplicitPermissions, - @UserIdInt int userId, @NonNull int[] updatedUserIds) { + @NonNull int[] userIds, @NonNull int[] updatedUserIds) { String pkgName = pkg.getPackageName(); ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>(); @@ -3305,33 +3325,35 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (!ps.hasInstallPermission(newPerm)) { BasePermission bp = mSettings.getPermissionLocked(newPerm); - if (!newPerm.equals(Manifest.permission.ACTIVITY_RECOGNITION)) { - ps.updatePermissionFlags(bp, - FLAG_PERMISSION_REVOKE_WHEN_REQUESTED, - FLAG_PERMISSION_REVOKE_WHEN_REQUESTED); - } - updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); + for (int userId : userIds) { + if (!newPerm.equals(Manifest.permission.ACTIVITY_RECOGNITION)) { + ps.updatePermissionFlags(bp, userId, + FLAG_PERMISSION_REVOKE_WHEN_REQUESTED, + FLAG_PERMISSION_REVOKE_WHEN_REQUESTED); + } + updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); - boolean inheritsFromInstallPerm = false; - for (int sourcePermNum = 0; sourcePermNum < sourcePerms.size(); - sourcePermNum++) { - if (ps.hasInstallPermission(sourcePerms.valueAt(sourcePermNum))) { - inheritsFromInstallPerm = true; - break; + boolean inheritsFromInstallPerm = false; + for (int sourcePermNum = 0; sourcePermNum < sourcePerms.size(); + sourcePermNum++) { + if (ps.hasInstallPermission(sourcePerms.valueAt(sourcePermNum))) { + inheritsFromInstallPerm = true; + break; + } } - } - if (!origPs.hasRequestedPermission(sourcePerms) - && !inheritsFromInstallPerm) { - // Both permissions are new so nothing to inherit. - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms - + " for " + pkgName + " as split permission is also new"); + if (!origPs.hasRequestedPermission(sourcePerms) + && !inheritsFromInstallPerm) { + // Both permissions are new so nothing to inherit. + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms + + " for " + pkgName + " as split permission is also new"); + } + } else { + // Inherit from new install or existing runtime permissions + inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms, + newPerm, ps, pkg, userId); } - } else { - // Inherit from new install or existing runtime permissions - inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms, - newPerm, ps, pkg); } } } @@ -3462,7 +3484,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } private boolean shouldGrantSignaturePermission(String perm, AndroidPackage pkg, - PackageSetting pkgSetting, BasePermission bp, UidPermissionState origPermissions) { + PackageSetting pkgSetting, BasePermission bp, PermissionsState origPermissions) { boolean oemPermission = bp.isOEM(); boolean vendorPrivilegedPermission = bp.isVendorPrivileged(); boolean privilegedPermission = bp.isPrivileged() || bp.isVendorPrivileged(); @@ -3738,13 +3760,12 @@ 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); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return false; } - return uidState.isPermissionReviewRequired(); + return permissionsState.isPermissionReviewRequired(userId); } private boolean isPackageRequestingPermission(AndroidPackage pkg, String permission) { @@ -3768,10 +3789,9 @@ 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); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return; } @@ -3796,7 +3816,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { && (supportsRuntimePermissions || !bp.isRuntimeOnly()) && (grantedPermissions == null || ArrayUtils.contains(grantedPermissions, permission))) { - final int flags = uidState.getPermissionFlags(permission); + final int flags = permissionsState.getPermissionFlags(permission, userId); if (supportsRuntimePermissions) { // Installer cannot change immutable permissions. if ((flags & immutableFlags) == 0) { @@ -3818,19 +3838,18 @@ public class PermissionManagerService extends IPermissionManager.Stub { private void setWhitelistedRestrictedPermissionsForUsers(@NonNull AndroidPackage pkg, @UserIdInt int[] userIds, @Nullable List<String> permissions, int callingUid, @PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) { + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); + return; + } + SparseArray<ArraySet<String>> oldGrantedRestrictedPermissions = new SparseArray<>(); boolean updatePermissions = false; final int permissionCount = pkg.getRequestedPermissions().size(); 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); @@ -3840,14 +3859,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { continue; } - if (uidState.hasPermission(permissionName)) { + if (permissionsState.hasPermission(permissionName, userId)) { if (oldGrantedRestrictedPermissions.get(userId) == null) { oldGrantedRestrictedPermissions.put(userId, new ArraySet<>()); } oldGrantedRestrictedPermissions.get(userId).add(permissionName); } - final int oldFlags = uidState.getPermissionFlags(permissionName); + final int oldFlags = permissionsState.getPermissionFlags(permissionName, userId); int newFlags = oldFlags; int mask = 0; @@ -3902,7 +3921,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { // as whitelisting trumps policy i.e. policy cannot grant a non // grantable permission. if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) { - final boolean isGranted = uidState.hasPermission(permissionName); + final boolean isGranted = permissionsState.hasPermission(permissionName, + userId); if (!isWhitelisted && isGranted) { mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED; newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED; @@ -3938,13 +3958,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int j = 0; j < oldGrantedCount; j++) { final String permission = 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); + final PermissionsState newPermissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); continue; } - if (!newUidState.hasPermission(permission)) { + if (!newPermissionsState.hasPermission(permission, userId)) { callback.onPermissionRevoked(pkg.getUid(), userId, null); break; } @@ -3993,10 +4012,9 @@ 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); + PermissionsState permissionsState = getPermissionsState(deletedPs.pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + deletedPs.pkg.getPackageName()); continue; } @@ -4018,15 +4036,25 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } + // Try to revoke as an install permission which is for all users. // The package is gone - no need to keep flags for applying policy. - uidState.updatePermissionFlags(bp, PackageManager.MASK_PERMISSION_FLAGS_ALL, 0); + permissionsState.updatePermissionFlags(bp, userId, + PackageManager.MASK_PERMISSION_FLAGS_ALL, 0); + + if (permissionsState.revokeInstallPermission(bp) + == PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) { + affectedUserId = UserHandle.USER_ALL; + } // Try to revoke as a runtime permission which is per user. - // TODO(zhanghai): This doesn't make sense. revokePermission() doesn't fail, and why are - // we only killing the uid when gids changed, instead of any permission change? - if (uidState.revokePermission(bp) + if (permissionsState.revokeRuntimePermission(bp, userId) == PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) { - affectedUserId = userId; + if (affectedUserId == UserHandle.USER_NULL) { + affectedUserId = userId; + } else if (affectedUserId != userId) { + // Multiple users affected. + affectedUserId = UserHandle.USER_ALL; + } } } @@ -4034,12 +4062,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @GuardedBy("mLock") - private boolean revokeUnusedSharedUserPermissionsLocked( - List<AndroidPackage> pkgList, UidPermissionState uidState) { + private int[] revokeUnusedSharedUserPermissionsLocked( + List<AndroidPackage> pkgList, PermissionsState permissionsState, int[] allUserIds) { // Collect all used permissions in the UID final ArraySet<String> usedPermissions = new ArraySet<>(); if (pkgList == null || pkgList.size() == 0) { - return false; + return EmptyArray.INT; } for (AndroidPackage pkg : pkgList) { if (pkg.getRequestedPermissions().isEmpty()) { @@ -4055,27 +4083,44 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - boolean runtimePermissionChanged = false; - - // Prune permissions - final List<com.android.server.pm.permission.PermissionState> permissionStates = - uidState.getPermissionStates(); - final int permissionStatesSize = permissionStates.size(); - for (int i = permissionStatesSize - 1; i >= 0; i--) { - PermissionState permissionState = permissionStates.get(i); + // Prune install permissions + List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates(); + final int installPermCount = installPermStates.size(); + for (int i = installPermCount - 1; i >= 0; i--) { + PermissionState permissionState = installPermStates.get(i); if (!usedPermissions.contains(permissionState.getName())) { BasePermission bp = mSettings.getPermissionLocked(permissionState.getName()); if (bp != null) { - uidState.revokePermission(bp); - uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL, 0); - if (permissionState.isRuntime()) { - runtimePermissionChanged = true; + permissionsState.revokeInstallPermission(bp); + permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, + MASK_PERMISSION_FLAGS_ALL, 0); + } + } + } + + int[] runtimePermissionChangedUserIds = EmptyArray.INT; + + // Prune runtime permissions + for (int userId : allUserIds) { + List<PermissionState> runtimePermStates = permissionsState + .getRuntimePermissionStates(userId); + final int runtimePermCount = runtimePermStates.size(); + for (int i = runtimePermCount - 1; i >= 0; i--) { + PermissionState permissionState = runtimePermStates.get(i); + if (!usedPermissions.contains(permissionState.getName())) { + BasePermission bp = mSettings.getPermissionLocked(permissionState.getName()); + if (bp != null) { + permissionsState.revokeRuntimePermission(bp, userId); + permissionsState.updatePermissionFlags(bp, userId, + MASK_PERMISSION_FLAGS_ALL, 0); + runtimePermissionChangedUserIds = ArrayUtils.appendInt( + runtimePermissionChangedUserIds, userId); } } } } - return runtimePermissionChanged; + return runtimePermissionChangedUserIds; } /** @@ -4323,19 +4368,15 @@ 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; - } - if (uidState.getPermissionState(bp.getName()) != null) { - uidState.revokePermission(bp); - uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL, - 0); - } + final PermissionsState permissionsState = getPermissionsState(p); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + p.getPackageName()); + return; + } + if (permissionsState.getInstallPermissionState(bp.getName()) != null) { + permissionsState.revokeInstallPermission(bp); + permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, + MASK_PERMISSION_FLAGS_ALL, 0); } }); } @@ -4743,124 +4784,62 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Nullable - private UidPermissionState getUidState(@NonNull PackageSetting ps, - @UserIdInt int userId) { - return getUidState(ps.getAppId(), userId); + private PermissionsState getPermissionsState(@NonNull PackageSetting ps) { + return getPermissionsState(ps.getAppId()); } @Nullable - private UidPermissionState getUidState(@NonNull AndroidPackage pkg, - @UserIdInt int userId) { - return getUidState(pkg.getUid(), userId); + private PermissionsState getPermissionsState(@NonNull AndroidPackage pkg) { + return getPermissionsState(pkg.getUid()); } @Nullable - private UidPermissionState getUidState(int appId, @UserIdInt int userId) { + private PermissionsState getPermissionsState(int appId) { synchronized (mLock) { - final UserPermissionState userState = mState.getUserState(userId); - if (userState == null) { - return null; - } - return userState.getUidState(appId); + return mAppIdStates.get(appId); } } - private void removeAppState(int appId) { + @Nullable + private PermissionsState getOrCreatePermissionsState(@NonNull PackageSetting ps) { + return getOrCreatePermissionsState(ps.getAppId()); + } + + @Nullable + private PermissionsState getOrCreatePermissionsState(int appId) { synchronized (mLock) { - final int[] userIds = mState.getUserIds(); - for (final int userId : userIds) { - final UserPermissionState userState = mState.getUserState(userId); - userState.removeUidState(appId); + PermissionsState state = mAppIdStates.get(appId); + if (state == null) { + state = new PermissionsState(); + mAppIdStates.put(appId, state); } + return state; } } - private void readStateFromPackageSettings() { - final int[] userIds = getAllUserIds(); - mPackageManagerInt.forEachPackageSetting(ps -> { - final int appId = ps.getAppId(); - final PermissionsState permissionsState = ps.getPermissionsState(); + private void removePermissionsState(int appId) { + synchronized (mLock) { + mAppIdStates.remove(appId); + } + } + private void readPermissionsStateFromPackageSettings() { + mPackageManagerInt.forEachPackageSetting(ps -> { synchronized (mLock) { - for (final int userId : userIds) { - final UserPermissionState userState = mState.getOrCreateUserState(userId); - - userState.setInstallPermissionsFixed(ps.name, ps.areInstallPermissionsFixed()); - final UidPermissionState uidState = userState.getOrCreateUidState(appId); - uidState.reset(); - uidState.setGlobalGids(permissionsState.getGlobalGids()); - uidState.setMissing(permissionsState.isMissing(userId)); - readStateFromPermissionStates(uidState, - permissionsState.getInstallPermissionStates(), false); - readStateFromPermissionStates(uidState, - permissionsState.getRuntimePermissionStates(userId), true); - } + mAppIdStates.put(ps.getAppId(), new PermissionsState(ps.getPermissionsState())); } }); } - private void readStateFromPermissionStates(@NonNull UidPermissionState uidState, - @NonNull List<PermissionsState.PermissionState> permissionStates, boolean isRuntime) { - final int permissionStatesSize = permissionStates.size(); - for (int i = 0; i < permissionStatesSize; i++) { - final PermissionsState.PermissionState permissionState = permissionStates.get(i); - final BasePermission permission = permissionState.getPermission(); - uidState.putPermissionState(permission, isRuntime, permissionState.isGranted(), - permissionState.getFlags()); - } - } - - private void writeStateToPackageSettings() { - final int[] userIds = mState.getUserIds(); + private void writePermissionsStateToPackageSettings() { mPackageManagerInt.forEachPackageSetting(ps -> { - ps.setInstallPermissionsFixed(false); - final PermissionsState permissionsState = ps.getPermissionsState(); - permissionsState.reset(); - final int appId = ps.getAppId(); - synchronized (mLock) { - for (final int userId : userIds) { - final UserPermissionState userState = mState.getUserState(userId); - if (userState == null) { - Slog.e(TAG, "Missing user state for " + userId); - continue; - } - - if (userState.areInstallPermissionsFixed(ps.name)) { - ps.setInstallPermissionsFixed(true); - } - - final UidPermissionState uidState = userState.getUidState(appId); - if (uidState == null) { - Slog.e(TAG, "Missing permission state for " + ps.name + " and user " - + userId); - continue; - } - - permissionsState.setGlobalGids(uidState.getGlobalGids()); - permissionsState.setMissing(uidState.isMissing(), userId); - 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 BasePermission permission = permissionState.getPermission(); - if (permissionState.isGranted()) { - if (permissionState.isRuntime()) { - permissionsState.grantRuntimePermission(permission, userId); - } else { - permissionsState.grantInstallPermission(permission); - } - } - final int flags = permissionState.getFlags(); - if (flags != 0) { - final int flagsUserId = permissionState.isRuntime() ? userId - : UserHandle.USER_ALL; - permissionsState.updatePermissionFlags(permission, flagsUserId, flags, - flags); - } - } + final PermissionsState permissionsState = mAppIdStates.get(ps.getAppId()); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + ps.name); + return; } + ps.getPermissionsState().copyFrom(permissionsState); } }); } @@ -4897,12 +4876,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { PermissionManagerService.this.removeAllPermissions(pkg, chatty); } @Override - public void readStateFromPackageSettingsTEMP() { - PermissionManagerService.this.readStateFromPackageSettings(); + public void readPermissionsStateFromPackageSettingsTEMP() { + PermissionManagerService.this.readPermissionsStateFromPackageSettings(); } @Override - public void writeStateToPackageSettingsTEMP() { - PermissionManagerService.this.writeStateToPackageSettings(); + public void writePermissionsStateToPackageSettingsTEMP() { + PermissionManagerService.this.writePermissionsStateToPackageSettings(); } @Override public void onUserRemoved(@UserIdInt int userId) { @@ -4910,7 +4889,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Override public void removePermissionsStateTEMP(int appId) { - PermissionManagerService.this.removeAppState(appId); + PermissionManagerService.this.removePermissionsState(appId); } @Override @UserIdInt diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index 7f6a1d4284d2..f319bf495e8b 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -266,21 +266,21 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); /** - * Read permission state from package settings. + * Read {@code PermissionsState} from package settings. * * TODO(zhanghai): This is a temporary method because we should not expose * {@code PackageSetting} which is a implementation detail that permission should not know. * Instead, it should retrieve the legacy state via a defined API. */ - public abstract void readStateFromPackageSettingsTEMP(); + public abstract void readPermissionsStateFromPackageSettingsTEMP(); /** - * Write permission state to package settings. + * Write {@code PermissionsState} from to settings. * * TODO(zhanghai): This is a temporary method and should be removed once we migrated persistence * for permission. */ - public abstract void writeStateToPackageSettingsTEMP(); + public abstract void writePermissionsStateToPackageSettingsTEMP(); /** * Notify that a user has been removed and its permission state should be removed as well. diff --git a/services/core/java/com/android/server/pm/permission/PermissionState.java b/services/core/java/com/android/server/pm/permission/PermissionState.java deleted file mode 100644 index 2ed9a50353d4..000000000000 --- a/services/core/java/com/android/server/pm/permission/PermissionState.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.pm.permission; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.UserIdInt; - -import com.android.internal.annotations.GuardedBy; - -/** - * State for a single permission. - */ -public final class PermissionState { - - @NonNull - private final BasePermission mPermission; - - private final Object mLock = new Object(); - - @GuardedBy("mLock") - private boolean mRuntime; - - @GuardedBy("mLock") - private boolean mGranted; - - @GuardedBy("mLock") - private int mFlags; - - public PermissionState(@NonNull BasePermission permission, boolean isRuntime) { - mPermission = permission; - mRuntime = isRuntime; - } - - public PermissionState(@NonNull PermissionState other) { - this(other.mPermission, other.mRuntime); - - mGranted = other.mGranted; - mFlags = other.mFlags; - } - - @NonNull - public BasePermission getPermission() { - return mPermission; - } - - @NonNull - public String getName() { - return mPermission.getName(); - } - - @Nullable - public int[] computeGids(@UserIdInt int userId) { - return mPermission.computeGids(userId); - } - - public boolean isRuntime() { - synchronized (mLock) { - return mRuntime; - } - } - - public boolean isGranted() { - synchronized (mLock) { - return mGranted; - } - } - - public boolean grant() { - synchronized (mLock) { - if (mGranted) { - return false; - } - mGranted = true; - UidPermissionState.invalidateCache(); - return true; - } - } - - public boolean revoke() { - synchronized (mLock) { - if (!mGranted) { - return false; - } - mGranted = false; - UidPermissionState.invalidateCache(); - return true; - } - } - - public int getFlags() { - synchronized (mLock) { - return mFlags; - } - } - - public boolean updateFlags(int flagMask, int flagValues) { - synchronized (mLock) { - final int newFlags = flagValues & flagMask; - - // Okay to do before the modification because we hold the lock. - UidPermissionState.invalidateCache(); - - final int oldFlags = mFlags; - mFlags = (mFlags & ~flagMask) | newFlags; - return mFlags != oldFlags; - } - } - - public boolean isDefault() { - synchronized (mLock) { - return !mGranted && mFlags == 0; - } - } -} diff --git a/services/core/java/com/android/server/pm/permission/PermissionsState.java b/services/core/java/com/android/server/pm/permission/PermissionsState.java index 4fb2d5fc200e..bad59cb1b567 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionsState.java +++ b/services/core/java/com/android/server/pm/permission/PermissionsState.java @@ -86,10 +86,6 @@ public final class PermissionsState { copyFrom(prototype); } - public int[] getGlobalGids() { - return mGlobalGids; - } - /** * Sets the global gids, applicable to all users. * @@ -829,7 +825,7 @@ public final class PermissionsState { PermissionState userState = mUserStates.get(userId); if (userState == null) { - userState = new PermissionState(mPerm); + userState = new PermissionState(mPerm.getName()); mUserStates.put(userId, userState); } @@ -912,7 +908,7 @@ public final class PermissionsState { } return userState.mFlags != oldFlags; } else if (newFlags != 0) { - userState = new PermissionState(mPerm); + userState = new PermissionState(mPerm.getName()); userState.mFlags = newFlags; mUserStates.put(userId, userState); return true; @@ -933,16 +929,16 @@ public final class PermissionsState { } public static final class PermissionState { - private final BasePermission mPermission; + private final String mName; private boolean mGranted; private int mFlags; - public PermissionState(BasePermission permission) { - mPermission = permission; + public PermissionState(String name) { + mName = name; } public PermissionState(PermissionState other) { - mPermission = other.mPermission; + mName = other.mName; mGranted = other.mGranted; mFlags = other.mFlags; } @@ -951,12 +947,8 @@ public final class PermissionsState { return !mGranted && mFlags == 0; } - public BasePermission getPermission() { - return mPermission; - } - public String getName() { - return mPermission.getName(); + return mName; } public boolean isGranted() { diff --git a/services/core/java/com/android/server/pm/permission/UidPermissionState.java b/services/core/java/com/android/server/pm/permission/UidPermissionState.java deleted file mode 100644 index 4c047ffd30e8..000000000000 --- a/services/core/java/com/android/server/pm/permission/UidPermissionState.java +++ /dev/null @@ -1,574 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.pm.permission; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.UserIdInt; -import android.content.pm.PackageManager; -import android.util.ArrayMap; -import android.util.ArraySet; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.ArrayUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -/** - * Permission state for a UID. - * <p> - * This class is also responsible for keeping track of the Linux GIDs per - * user for a package or a shared user. The GIDs are computed as a set of - * the GIDs for all granted permissions' GIDs on a per user basis. - */ -public final class UidPermissionState { - /** The permission operation failed. */ - public static final int PERMISSION_OPERATION_FAILURE = -1; - - /** The permission operation succeeded and no gids changed. */ - public static final int PERMISSION_OPERATION_SUCCESS = 0; - - /** The permission operation succeeded and gids changed. */ - public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 1; - - private static final int[] NO_GIDS = {}; - - @NonNull - private final Object mLock = new Object(); - - @GuardedBy("mLock") - private ArrayMap<String, PermissionState> mPermissions; - - @NonNull - private int[] mGlobalGids = NO_GIDS; - - private boolean mMissing; - - private boolean mPermissionReviewRequired; - - public UidPermissionState() { - /* do nothing */ - } - - public UidPermissionState(@NonNull UidPermissionState prototype) { - copyFrom(prototype); - } - - /** - * Gets the global gids, applicable to all users. - */ - @NonNull - public int[] getGlobalGids() { - return mGlobalGids; - } - - /** - * Sets the global gids, applicable to all users. - * - * @param globalGids The global gids. - */ - public void setGlobalGids(@NonNull int[] globalGids) { - if (!ArrayUtils.isEmpty(globalGids)) { - mGlobalGids = Arrays.copyOf(globalGids, globalGids.length); - } - } - - static void invalidateCache() { - PackageManager.invalidatePackageInfoCache(); - } - - /** - * Initialized this instance from another one. - * - * @param other The other instance. - */ - public void copyFrom(@NonNull UidPermissionState other) { - if (other == this) { - return; - } - - synchronized (mLock) { - if (mPermissions != null) { - if (other.mPermissions == null) { - mPermissions = null; - } else { - mPermissions.clear(); - } - } - if (other.mPermissions != null) { - if (mPermissions == null) { - mPermissions = new ArrayMap<>(); - } - final int permissionCount = other.mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - String name = other.mPermissions.keyAt(i); - PermissionState permissionState = other.mPermissions.valueAt(i); - mPermissions.put(name, new PermissionState(permissionState)); - } - } - } - - mGlobalGids = NO_GIDS; - if (other.mGlobalGids != NO_GIDS) { - mGlobalGids = other.mGlobalGids.clone(); - } - - mMissing = other.mMissing; - - mPermissionReviewRequired = other.mPermissionReviewRequired; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final UidPermissionState other = (UidPermissionState) obj; - - synchronized (mLock) { - if (mPermissions == null) { - if (other.mPermissions != null) { - return false; - } - } else if (!mPermissions.equals(other.mPermissions)) { - return false; - } - } - - if (mMissing != other.mMissing) { - return false; - } - - if (mPermissionReviewRequired != other.mPermissionReviewRequired) { - return false; - } - return Arrays.equals(mGlobalGids, other.mGlobalGids); - } - - /** - * Check whether the permissions state is missing for a user. This can happen if permission - * state is rolled back and we'll need to generate a reasonable default state to keep the app - * usable. - */ - public boolean isMissing() { - return mMissing; - } - - /** - * Set whether the permissions state is missing for a user. This can happen if permission state - * is rolled back and we'll need to generate a reasonable default state to keep the app usable. - */ - public void setMissing(boolean missing) { - mMissing = missing; - } - - public boolean isPermissionReviewRequired() { - return mPermissionReviewRequired; - } - - /** - * Gets whether the state has a given permission. - * - * @param name The permission name. - * @return Whether the state has the permission. - */ - public boolean hasPermission(@NonNull String name) { - synchronized (mLock) { - if (mPermissions == null) { - return false; - } - PermissionState permissionState = mPermissions.get(name); - return permissionState != null && permissionState.isGranted(); - } - } - - /** - * Gets whether the state has a given install permission. - * - * @param name The permission name. - * @return Whether the state has the install permission. - */ - public boolean hasInstallPermission(@NonNull String name) { - synchronized (mLock) { - if (mPermissions == null) { - return false; - } - PermissionState permissionState = mPermissions.get(name); - return permissionState != null && permissionState.isGranted() - && !permissionState.isRuntime(); - } - } - - /** - * Returns whether the state has any known request for the given permission name, - * whether or not it has been granted. - * - * @deprecated Not all requested permissions may be here. - */ - @Deprecated - public boolean hasRequestedPermission(@NonNull ArraySet<String> names) { - synchronized (mLock) { - if (mPermissions == null) { - return false; - } - for (int i = names.size() - 1; i >= 0; i--) { - if (mPermissions.get(names.valueAt(i)) != null) { - return true; - } - } - } - - return false; - } - - /** - * Returns whether the state has any known request for the given permission name, - * whether or not it has been granted. - * - * @deprecated Not all requested permissions may be here. - */ - @Deprecated - public boolean hasRequestedPermission(@NonNull String name) { - return mPermissions != null && (mPermissions.get(name) != null); - } - - /** - * Gets all permissions for a given device user id regardless if they - * are install time or runtime permissions. - * - * @return The permissions or an empty set. - */ - @NonNull - public Set<String> getPermissions() { - synchronized (mLock) { - if (mPermissions == null) { - return Collections.emptySet(); - } - - Set<String> permissions = new ArraySet<>(mPermissions.size()); - - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - String permission = mPermissions.keyAt(i); - - if (hasPermission(permission)) { - permissions.add(permission); - } - } - - return permissions; - } - } - - /** - * Gets the flags for a permission. - * - * @param name The permission name. - * @return The permission state or null if no such. - */ - public int getPermissionFlags(@NonNull String name) { - PermissionState permState = getPermissionState(name); - if (permState != null) { - return permState.getFlags(); - } - return 0; - } - - /** - * Update the flags associated with a given permission. - * @param permission The permission whose flags to update. - * @param flagMask Mask for which flags to change. - * @param flagValues New values for the mask flags. - * @return Whether the permission flags changed. - */ - public boolean updatePermissionFlags(@NonNull BasePermission permission, int flagMask, - int flagValues) { - if (flagMask == 0) { - return false; - } - - PermissionState permissionState = ensurePermissionState(permission); - - final int oldFlags = permissionState.getFlags(); - - synchronized (mLock) { - final boolean updated = permissionState.updateFlags(flagMask, flagValues); - if (updated) { - final int newFlags = permissionState.getFlags(); - if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0 - && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { - mPermissionReviewRequired = true; - } else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0 - && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) { - if (mPermissionReviewRequired && !hasPermissionRequiringReview()) { - mPermissionReviewRequired = false; - } - } - } - return updated; - } - } - - private boolean hasPermissionRequiringReview() { - synchronized (mLock) { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - final PermissionState permission = mPermissions.valueAt(i); - if ((permission.getFlags() & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { - return true; - } - } - } - return false; - } - - public boolean updatePermissionFlagsForAllPermissions(int flagMask, int flagValues) { - synchronized (mLock) { - if (mPermissions == null) { - return false; - } - boolean changed = false; - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - PermissionState permissionState = mPermissions.valueAt(i); - changed |= permissionState.updateFlags(flagMask, flagValues); - } - return changed; - } - } - - /** - * Compute the Linux gids for a given device user from the permissions - * granted to this user. Note that these are computed to avoid additional - * state as they are rarely accessed. - * - * @param userId The device user id. - * @return The gids for the device user. - */ - @NonNull - public int[] computeGids(@UserIdInt int userId) { - int[] gids = mGlobalGids; - - synchronized (mLock) { - if (mPermissions != null) { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - PermissionState permissionState = mPermissions.valueAt(i); - if (!permissionState.isGranted()) { - continue; - } - final int[] permGids = permissionState.computeGids(userId); - if (permGids != NO_GIDS) { - gids = appendInts(gids, permGids); - } - } - } - } - - return gids; - } - - /** - * Compute the Linux gids for all device users from the permissions - * granted to these users. - * - * @return The gids for all device users. - */ - @NonNull - public int[] computeGids(@NonNull int[] userIds) { - int[] gids = mGlobalGids; - - for (int userId : userIds) { - final int[] userGids = computeGids(userId); - gids = appendInts(gids, userGids); - } - - return gids; - } - - /** - * Resets the internal state of this object. - */ - public void reset() { - mGlobalGids = NO_GIDS; - - synchronized (mLock) { - mPermissions = null; - invalidateCache(); - } - - mMissing = false; - mPermissionReviewRequired = false; - } - - /** - * Gets the state for a permission or null if no such. - * - * @param name The permission name. - * @return The permission state. - */ - @Nullable - public PermissionState getPermissionState(@NonNull String name) { - synchronized (mLock) { - if (mPermissions == null) { - return null; - } - return mPermissions.get(name); - } - } - - /** - * Gets all permission states. - * - * @return The permission states or an empty set. - */ - @NonNull - public List<PermissionState> getPermissionStates() { - synchronized (mLock) { - if (mPermissions == null) { - return Collections.emptyList(); - } - return new ArrayList<>(mPermissions.values()); - } - } - - /** - * Put a permission state. - */ - public void putPermissionState(@NonNull BasePermission permission, boolean isRuntime, - boolean isGranted, int flags) { - synchronized (mLock) { - ensureNoPermissionState(permission.name); - PermissionState permissionState = ensurePermissionState(permission, isRuntime); - if (isGranted) { - permissionState.grant(); - } - permissionState.updateFlags(flags, flags); - if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { - mPermissionReviewRequired = true; - } - } - } - - /** - * Grant a permission. - * - * @param permission The permission to grant. - * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, - * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link - * #PERMISSION_OPERATION_FAILURE}. - */ - public int grantPermission(@NonNull BasePermission permission) { - if (hasPermission(permission.getName())) { - return PERMISSION_OPERATION_SUCCESS; - } - - PermissionState permissionState = ensurePermissionState(permission); - - if (!permissionState.grant()) { - return PERMISSION_OPERATION_FAILURE; - } - - return permission.hasGids() ? PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED - : PERMISSION_OPERATION_SUCCESS; - } - - /** - * Revoke a permission. - * - * @param permission The permission to revoke. - * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, - * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link - * #PERMISSION_OPERATION_FAILURE}. - */ - public int revokePermission(@NonNull BasePermission permission) { - final String permissionName = permission.getName(); - if (!hasPermission(permissionName)) { - return PERMISSION_OPERATION_SUCCESS; - } - - PermissionState permissionState; - synchronized (mLock) { - permissionState = mPermissions.get(permissionName); - } - - if (!permissionState.revoke()) { - return PERMISSION_OPERATION_FAILURE; - } - - if (permissionState.isDefault()) { - ensureNoPermissionState(permissionName); - } - - return permission.hasGids() ? PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED - : PERMISSION_OPERATION_SUCCESS; - } - - // TODO: fix this to use arraycopy and append all ints in one go - private static int[] appendInts(int[] current, int[] added) { - if (current != null && added != null) { - for (int guid : added) { - current = ArrayUtils.appendInt(current, guid); - } - } - return current; - } - - @NonNull - private PermissionState ensurePermissionState(@NonNull BasePermission permission) { - return ensurePermissionState(permission, permission.isRuntime()); - } - - @NonNull - private PermissionState ensurePermissionState(@NonNull BasePermission permission, - boolean isRuntime) { - final String permissionName = permission.getName(); - synchronized (mLock) { - if (mPermissions == null) { - mPermissions = new ArrayMap<>(); - } - PermissionState permissionState = mPermissions.get(permissionName); - if (permissionState == null) { - permissionState = new PermissionState(permission, isRuntime); - mPermissions.put(permissionName, permissionState); - } - return permissionState; - } - } - - private void ensureNoPermissionState(@NonNull String name) { - synchronized (mLock) { - if (mPermissions == null) { - return; - } - mPermissions.remove(name); - if (mPermissions.isEmpty()) { - mPermissions = null; - } - } - } -} diff --git a/services/core/java/com/android/server/pm/permission/UserPermissionState.java b/services/core/java/com/android/server/pm/permission/UserPermissionState.java deleted file mode 100644 index 7f55cb161e40..000000000000 --- a/services/core/java/com/android/server/pm/permission/UserPermissionState.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.pm.permission; - -import android.annotation.AppIdInt; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.UserHandle; -import android.util.ArraySet; -import android.util.SparseArray; - -import com.android.internal.annotations.GuardedBy; - -/** - * Permission state for a user. - */ -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); - } - } - - public void setInstallPermissionsFixed(@NonNull String packageName, boolean fixed) { - synchronized (mLock) { - if (fixed) { - mInstallPermissionsFixed.add(packageName); - } else { - mInstallPermissionsFixed.remove(packageName); - } - } - } - - @Nullable - public UidPermissionState getUidState(@AppIdInt int appId) { - checkAppId(appId); - synchronized (mLock) { - 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; - } - } - - public void removeUidState(@AppIdInt int appId) { - checkAppId(appId); - synchronized (mLock) { - mUidStates.delete(appId); - } - } - - private void checkAppId(@AppIdInt int appId) { - if (UserHandle.getUserId(appId) != 0) { - throw new IllegalArgumentException(appId + " is not an app ID"); - } - } -} |