/*
|
* 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.content.pm.PackageManager;
|
import android.os.UserHandle;
|
import android.util.ArrayMap;
|
import android.util.ArraySet;
|
import android.util.SparseArray;
|
import android.util.SparseBooleanArray;
|
|
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;
|
import com.android.internal.annotations.GuardedBy;
|
|
/**
|
* This class encapsulates the permissions for a package or a shared user.
|
* <p>
|
* There are two types of permissions: install (granted at installation)
|
* and runtime (granted at runtime). Install permissions are granted to
|
* all device users while runtime permissions are granted explicitly to
|
* specific users.
|
* </p>
|
* <p>
|
* The permissions are kept on a per device user basis. For example, an
|
* application may have some runtime permissions granted under the device
|
* owner but not granted under the secondary user.
|
* <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.
|
* </p>
|
*/
|
public final class PermissionsState {
|
|
/** 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 = {};
|
|
private final Object mLock = new Object();
|
|
@GuardedBy("mLock")
|
private ArrayMap<String, PermissionData> mPermissions;
|
|
private int[] mGlobalGids = NO_GIDS;
|
|
private SparseBooleanArray mPermissionReviewRequired;
|
|
public PermissionsState() {
|
/* do nothing */
|
}
|
|
public PermissionsState(PermissionsState prototype) {
|
copyFrom(prototype);
|
}
|
|
/**
|
* Sets the global gids, applicable to all users.
|
*
|
* @param globalGids The global gids.
|
*/
|
public void setGlobalGids(int[] globalGids) {
|
if (!ArrayUtils.isEmpty(globalGids)) {
|
mGlobalGids = Arrays.copyOf(globalGids, globalGids.length);
|
}
|
}
|
|
/**
|
* Initialized this instance from another one.
|
*
|
* @param other The other instance.
|
*/
|
public void copyFrom(PermissionsState 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);
|
PermissionData permissionData = other.mPermissions.valueAt(i);
|
mPermissions.put(name, new PermissionData(permissionData));
|
}
|
}
|
}
|
|
mGlobalGids = NO_GIDS;
|
if (other.mGlobalGids != NO_GIDS) {
|
mGlobalGids = Arrays.copyOf(other.mGlobalGids,
|
other.mGlobalGids.length);
|
}
|
|
if (mPermissionReviewRequired != null) {
|
if (other.mPermissionReviewRequired == null) {
|
mPermissionReviewRequired = null;
|
} else {
|
mPermissionReviewRequired.clear();
|
}
|
}
|
if (other.mPermissionReviewRequired != null) {
|
if (mPermissionReviewRequired == null) {
|
mPermissionReviewRequired = new SparseBooleanArray();
|
}
|
final int userCount = other.mPermissionReviewRequired.size();
|
for (int i = 0; i < userCount; i++) {
|
final boolean reviewRequired = other.mPermissionReviewRequired.valueAt(i);
|
mPermissionReviewRequired.put(other.mPermissionReviewRequired.keyAt(i),
|
reviewRequired);
|
}
|
}
|
}
|
|
@Override
|
public boolean equals(Object obj) {
|
if (this == obj) {
|
return true;
|
}
|
if (obj == null) {
|
return false;
|
}
|
if (getClass() != obj.getClass()) {
|
return false;
|
}
|
final PermissionsState other = (PermissionsState) obj;
|
|
synchronized (mLock) {
|
if (mPermissions == null) {
|
if (other.mPermissions != null) {
|
return false;
|
}
|
} else if (!mPermissions.equals(other.mPermissions)) {
|
return false;
|
}
|
}
|
|
if (mPermissionReviewRequired == null) {
|
if (other.mPermissionReviewRequired != null) {
|
return false;
|
}
|
} else if (!mPermissionReviewRequired.equals(other.mPermissionReviewRequired)) {
|
return false;
|
}
|
return Arrays.equals(mGlobalGids, other.mGlobalGids);
|
}
|
|
public boolean isPermissionReviewRequired(int userId) {
|
return mPermissionReviewRequired != null && mPermissionReviewRequired.get(userId);
|
}
|
|
/**
|
* Grant an install 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 grantInstallPermission(BasePermission permission) {
|
return grantPermission(permission, UserHandle.USER_ALL);
|
}
|
|
/**
|
* Revoke an install 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 revokeInstallPermission(BasePermission permission) {
|
return revokePermission(permission, UserHandle.USER_ALL);
|
}
|
|
/**
|
* Grant a runtime permission for a given device user.
|
*
|
* @param permission The permission to grant.
|
* @param userId The device user id.
|
* @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 grantRuntimePermission(BasePermission permission, int userId) {
|
enforceValidUserId(userId);
|
if (userId == UserHandle.USER_ALL) {
|
return PERMISSION_OPERATION_FAILURE;
|
}
|
return grantPermission(permission, userId);
|
}
|
|
/**
|
* Revoke a runtime permission for a given device user.
|
*
|
* @param permission The permission to revoke.
|
* @param userId The device user id.
|
* @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 revokeRuntimePermission(BasePermission permission, int userId) {
|
enforceValidUserId(userId);
|
if (userId == UserHandle.USER_ALL) {
|
return PERMISSION_OPERATION_FAILURE;
|
}
|
return revokePermission(permission, userId);
|
}
|
|
/**
|
* Gets whether this state has a given runtime permission for a
|
* given device user id.
|
*
|
* @param name The permission name.
|
* @param userId The device user id.
|
* @return Whether this state has the permission.
|
*/
|
public boolean hasRuntimePermission(String name, int userId) {
|
enforceValidUserId(userId);
|
return !hasInstallPermission(name) && hasPermission(name, userId);
|
}
|
|
/**
|
* Gets whether this state has a given install permission.
|
*
|
* @param name The permission name.
|
* @return Whether this state has the permission.
|
*/
|
public boolean hasInstallPermission(String name) {
|
return hasPermission(name, UserHandle.USER_ALL);
|
}
|
|
/**
|
* Gets whether the state has a given permission for the specified
|
* user, regardless if this is an install or a runtime permission.
|
*
|
* @param name The permission name.
|
* @param userId The device user id.
|
* @return Whether the user has the permission.
|
*/
|
public boolean hasPermission(String name, int userId) {
|
enforceValidUserId(userId);
|
|
synchronized (mLock) {
|
if (mPermissions == null) {
|
return false;
|
}
|
PermissionData permissionData = mPermissions.get(name);
|
|
return permissionData != null && permissionData.isGranted(userId);
|
}
|
|
}
|
|
/**
|
* Returns whether the state has any known request for the given permission name,
|
* whether or not it has been granted.
|
*/
|
public boolean hasRequestedPermission(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.
|
*/
|
public boolean hasRequestedPermission(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.
|
*
|
* @param userId The device user id.
|
* @return The permissions or an empty set.
|
*/
|
public Set<String> getPermissions(int userId) {
|
enforceValidUserId(userId);
|
|
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 (hasInstallPermission(permission)) {
|
permissions.add(permission);
|
continue;
|
}
|
|
if (userId != UserHandle.USER_ALL) {
|
if (hasRuntimePermission(permission, userId)) {
|
permissions.add(permission);
|
}
|
}
|
}
|
|
return permissions;
|
}
|
}
|
|
/**
|
* Gets the state for an install permission or null if no such.
|
*
|
* @param name The permission name.
|
* @return The permission state.
|
*/
|
public PermissionState getInstallPermissionState(String name) {
|
return getPermissionState(name, UserHandle.USER_ALL);
|
}
|
|
/**
|
* Gets the state for a runtime permission or null if no such.
|
*
|
* @param name The permission name.
|
* @param userId The device user id.
|
* @return The permission state.
|
*/
|
public PermissionState getRuntimePermissionState(String name, int userId) {
|
enforceValidUserId(userId);
|
return getPermissionState(name, userId);
|
}
|
|
/**
|
* Gets all install permission states.
|
*
|
* @return The permission states or an empty set.
|
*/
|
public List<PermissionState> getInstallPermissionStates() {
|
return getPermissionStatesInternal(UserHandle.USER_ALL);
|
}
|
|
/**
|
* Gets all runtime permission states.
|
*
|
* @return The permission states or an empty set.
|
*/
|
public List<PermissionState> getRuntimePermissionStates(int userId) {
|
enforceValidUserId(userId);
|
return getPermissionStatesInternal(userId);
|
}
|
|
/**
|
* Gets the flags for a permission regardless if it is install or
|
* runtime permission.
|
*
|
* @param name The permission name.
|
* @return The permission state or null if no such.
|
*/
|
public int getPermissionFlags(String name, int userId) {
|
PermissionState installPermState = getInstallPermissionState(name);
|
if (installPermState != null) {
|
return installPermState.getFlags();
|
}
|
PermissionState runtimePermState = getRuntimePermissionState(name, userId);
|
if (runtimePermState != null) {
|
return runtimePermState.getFlags();
|
}
|
return 0;
|
}
|
|
/**
|
* Update the flags associated with a given permission.
|
* @param permission The permission whose flags to update.
|
* @param userId The user for which 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(BasePermission permission, int userId,
|
int flagMask, int flagValues) {
|
enforceValidUserId(userId);
|
|
final boolean mayChangeFlags = flagValues != 0 || flagMask != 0;
|
|
synchronized (mLock) {
|
if (mPermissions == null) {
|
if (!mayChangeFlags) {
|
return false;
|
}
|
ensurePermissionData(permission);
|
}
|
}
|
|
PermissionData permissionData = null;
|
synchronized (mLock) {
|
permissionData = mPermissions.get(permission.getName());
|
}
|
|
if (permissionData == null) {
|
if (!mayChangeFlags) {
|
return false;
|
}
|
permissionData = ensurePermissionData(permission);
|
}
|
|
final int oldFlags = permissionData.getFlags(userId);
|
|
final boolean updated = permissionData.updateFlags(userId, flagMask, flagValues);
|
if (updated) {
|
final int newFlags = permissionData.getFlags(userId);
|
if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0
|
&& (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
|
if (mPermissionReviewRequired == null) {
|
mPermissionReviewRequired = new SparseBooleanArray();
|
}
|
mPermissionReviewRequired.put(userId, true);
|
} else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0
|
&& (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
|
if (mPermissionReviewRequired != null && !hasPermissionRequiringReview(userId)) {
|
mPermissionReviewRequired.delete(userId);
|
if (mPermissionReviewRequired.size() <= 0) {
|
mPermissionReviewRequired = null;
|
}
|
}
|
}
|
}
|
return updated;
|
}
|
|
private boolean hasPermissionRequiringReview(int userId) {
|
synchronized (mLock) {
|
final int permissionCount = mPermissions.size();
|
for (int i = 0; i < permissionCount; i++) {
|
final PermissionData permission = mPermissions.valueAt(i);
|
if ((permission.getFlags(userId)
|
& PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
|
return true;
|
}
|
}
|
}
|
|
return false;
|
}
|
|
public boolean updatePermissionFlagsForAllPermissions(
|
int userId, int flagMask, int flagValues) {
|
enforceValidUserId(userId);
|
|
synchronized (mLock) {
|
if (mPermissions == null) {
|
return false;
|
}
|
boolean changed = false;
|
final int permissionCount = mPermissions.size();
|
for (int i = 0; i < permissionCount; i++) {
|
PermissionData permissionData = mPermissions.valueAt(i);
|
changed |= permissionData.updateFlags(userId, 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.
|
*/
|
public int[] computeGids(int userId) {
|
enforceValidUserId(userId);
|
|
int[] gids = mGlobalGids;
|
|
synchronized (mLock) {
|
if (mPermissions != null) {
|
final int permissionCount = mPermissions.size();
|
for (int i = 0; i < permissionCount; i++) {
|
String permission = mPermissions.keyAt(i);
|
if (!hasPermission(permission, userId)) {
|
continue;
|
}
|
PermissionData permissionData = mPermissions.valueAt(i);
|
final int[] permGids = permissionData.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.
|
*/
|
public int[] computeGids(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;
|
}
|
|
mPermissionReviewRequired = null;
|
}
|
|
private PermissionState getPermissionState(String name, int userId) {
|
synchronized (mLock) {
|
if (mPermissions == null) {
|
return null;
|
}
|
PermissionData permissionData = mPermissions.get(name);
|
if (permissionData == null) {
|
return null;
|
}
|
|
return permissionData.getPermissionState(userId);
|
}
|
}
|
|
private List<PermissionState> getPermissionStatesInternal(int userId) {
|
enforceValidUserId(userId);
|
|
synchronized (mLock) {
|
if (mPermissions == null) {
|
return Collections.emptyList();
|
}
|
|
List<PermissionState> permissionStates = new ArrayList<>();
|
|
final int permissionCount = mPermissions.size();
|
for (int i = 0; i < permissionCount; i++) {
|
PermissionData permissionData = mPermissions.valueAt(i);
|
|
PermissionState permissionState = permissionData.getPermissionState(userId);
|
if (permissionState != null) {
|
permissionStates.add(permissionState);
|
}
|
}
|
|
return permissionStates;
|
}
|
}
|
|
private int grantPermission(BasePermission permission, int userId) {
|
if (hasPermission(permission.getName(), userId)) {
|
return PERMISSION_OPERATION_SUCCESS;
|
}
|
|
final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
|
final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
|
|
PermissionData permissionData = ensurePermissionData(permission);
|
|
if (!permissionData.grant(userId)) {
|
return PERMISSION_OPERATION_FAILURE;
|
}
|
|
if (hasGids) {
|
final int[] newGids = computeGids(userId);
|
if (oldGids.length != newGids.length) {
|
return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
|
}
|
}
|
|
return PERMISSION_OPERATION_SUCCESS;
|
}
|
|
private int revokePermission(BasePermission permission, int userId) {
|
final String permName = permission.getName();
|
if (!hasPermission(permName, userId)) {
|
return PERMISSION_OPERATION_SUCCESS;
|
}
|
|
final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
|
final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
|
|
PermissionData permissionData = null;
|
synchronized (mLock) {
|
permissionData = mPermissions.get(permName);
|
}
|
|
if (!permissionData.revoke(userId)) {
|
return PERMISSION_OPERATION_FAILURE;
|
}
|
|
if (permissionData.isDefault()) {
|
ensureNoPermissionData(permName);
|
}
|
|
if (hasGids) {
|
final int[] newGids = computeGids(userId);
|
if (oldGids.length != newGids.length) {
|
return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
|
}
|
}
|
|
return 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;
|
}
|
|
private static void enforceValidUserId(int userId) {
|
if (userId != UserHandle.USER_ALL && userId < 0) {
|
throw new IllegalArgumentException("Invalid userId:" + userId);
|
}
|
}
|
|
private PermissionData ensurePermissionData(BasePermission permission) {
|
final String permName = permission.getName();
|
|
synchronized (mLock) {
|
if (mPermissions == null) {
|
mPermissions = new ArrayMap<>();
|
}
|
PermissionData permissionData = mPermissions.get(permName);
|
if (permissionData == null) {
|
permissionData = new PermissionData(permission);
|
mPermissions.put(permName, permissionData);
|
}
|
return permissionData;
|
}
|
|
}
|
|
private void ensureNoPermissionData(String name) {
|
synchronized (mLock) {
|
if (mPermissions == null) {
|
return;
|
}
|
mPermissions.remove(name);
|
if (mPermissions.isEmpty()) {
|
mPermissions = null;
|
}
|
}
|
|
}
|
|
private static final class PermissionData {
|
private final BasePermission mPerm;
|
private SparseArray<PermissionState> mUserStates = new SparseArray<>();
|
|
public PermissionData(BasePermission perm) {
|
mPerm = perm;
|
}
|
|
public PermissionData(PermissionData other) {
|
this(other.mPerm);
|
final int otherStateCount = other.mUserStates.size();
|
for (int i = 0; i < otherStateCount; i++) {
|
final int otherUserId = other.mUserStates.keyAt(i);
|
PermissionState otherState = other.mUserStates.valueAt(i);
|
mUserStates.put(otherUserId, new PermissionState(otherState));
|
}
|
}
|
|
public int[] computeGids(int userId) {
|
return mPerm.computeGids(userId);
|
}
|
|
public boolean isGranted(int userId) {
|
if (isInstallPermission()) {
|
userId = UserHandle.USER_ALL;
|
}
|
|
PermissionState userState = mUserStates.get(userId);
|
if (userState == null) {
|
return false;
|
}
|
|
return userState.mGranted;
|
}
|
|
public boolean grant(int userId) {
|
if (!isCompatibleUserId(userId)) {
|
return false;
|
}
|
|
if (isGranted(userId)) {
|
return false;
|
}
|
|
PermissionState userState = mUserStates.get(userId);
|
if (userState == null) {
|
userState = new PermissionState(mPerm.getName());
|
mUserStates.put(userId, userState);
|
}
|
|
userState.mGranted = true;
|
|
return true;
|
}
|
|
public boolean revoke(int userId) {
|
if (!isCompatibleUserId(userId)) {
|
return false;
|
}
|
|
if (!isGranted(userId)) {
|
return false;
|
}
|
|
PermissionState userState = mUserStates.get(userId);
|
userState.mGranted = false;
|
|
if (userState.isDefault()) {
|
mUserStates.remove(userId);
|
}
|
|
return true;
|
}
|
|
public PermissionState getPermissionState(int userId) {
|
return mUserStates.get(userId);
|
}
|
|
public int getFlags(int userId) {
|
PermissionState userState = mUserStates.get(userId);
|
if (userState != null) {
|
return userState.mFlags;
|
}
|
return 0;
|
}
|
|
public boolean isDefault() {
|
return mUserStates.size() <= 0;
|
}
|
|
public static boolean isInstallPermissionKey(int userId) {
|
return userId == UserHandle.USER_ALL;
|
}
|
|
public boolean updateFlags(int userId, int flagMask, int flagValues) {
|
if (isInstallPermission()) {
|
userId = UserHandle.USER_ALL;
|
}
|
|
if (!isCompatibleUserId(userId)) {
|
return false;
|
}
|
|
final int newFlags = flagValues & flagMask;
|
|
PermissionState userState = mUserStates.get(userId);
|
if (userState != null) {
|
final int oldFlags = userState.mFlags;
|
userState.mFlags = (userState.mFlags & ~flagMask) | newFlags;
|
if (userState.isDefault()) {
|
mUserStates.remove(userId);
|
}
|
return userState.mFlags != oldFlags;
|
} else if (newFlags != 0) {
|
userState = new PermissionState(mPerm.getName());
|
userState.mFlags = newFlags;
|
mUserStates.put(userId, userState);
|
return true;
|
}
|
|
return false;
|
}
|
|
private boolean isCompatibleUserId(int userId) {
|
return isDefault() || !(isInstallPermission() ^ isInstallPermissionKey(userId));
|
}
|
|
private boolean isInstallPermission() {
|
return mUserStates.size() == 1
|
&& mUserStates.get(UserHandle.USER_ALL) != null;
|
}
|
}
|
|
public static final class PermissionState {
|
private final String mName;
|
private boolean mGranted;
|
private int mFlags;
|
|
public PermissionState(String name) {
|
mName = name;
|
}
|
|
public PermissionState(PermissionState other) {
|
mName = other.mName;
|
mGranted = other.mGranted;
|
mFlags = other.mFlags;
|
}
|
|
public boolean isDefault() {
|
return !mGranted && mFlags == 0;
|
}
|
|
public String getName() {
|
return mName;
|
}
|
|
public boolean isGranted() {
|
return mGranted;
|
}
|
|
public int getFlags() {
|
return mFlags;
|
}
|
}
|
}
|