Merge "Revert "Make all permissions per-user.""

This commit is contained in:
TreeHugger Robot
2020-09-14 19:05:44 +00:00
committed by Android (Google) Code Review
10 changed files with 570 additions and 1489 deletions

View File

@@ -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. -->

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}
}

View File

@@ -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.

View File

@@ -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;
}
}
}

View File

@@ -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() {

View File

@@ -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;
}
}
}
}

View File

@@ -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");
}
}
}