Merge "Revert "Make all permissions per-user.""
This commit is contained in:
committed by
Android (Google) Code Review
commit
c7eaa75e49
@@ -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. -->
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user