Merge changes from topic "AlwaysKeepAppOpsSynced" into qt-dev
* changes: Avoid overiding bg perm app-op for pre-M apps Also trigger PermPolicySvc on app-ops changes Combine successive PermPolicySvc syncs Always use PermMgrSrv APIs to change permission
This commit is contained in:
committed by
Android (Google) Code Review
commit
bf5506b240
@@ -111,9 +111,6 @@ import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFile
|
|||||||
import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
|
import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
|
||||||
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
|
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
|
||||||
import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
|
import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
|
||||||
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
|
|
||||||
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
|
|
||||||
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
|
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
@@ -294,6 +291,7 @@ import com.android.internal.util.ConcurrentUtils;
|
|||||||
import com.android.internal.util.DumpUtils;
|
import com.android.internal.util.DumpUtils;
|
||||||
import com.android.internal.util.FastXmlSerializer;
|
import com.android.internal.util.FastXmlSerializer;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
import com.android.internal.util.IntPair;
|
||||||
import com.android.internal.util.Preconditions;
|
import com.android.internal.util.Preconditions;
|
||||||
import com.android.server.AttributeCache;
|
import com.android.server.AttributeCache;
|
||||||
import com.android.server.DeviceIdleController;
|
import com.android.server.DeviceIdleController;
|
||||||
@@ -19801,6 +19799,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String packageName = ps.pkg.packageName;
|
||||||
|
|
||||||
// These are flags that can change base on user actions.
|
// These are flags that can change base on user actions.
|
||||||
final int userSettableMask = FLAG_PERMISSION_USER_SET
|
final int userSettableMask = FLAG_PERMISSION_USER_SET
|
||||||
| FLAG_PERMISSION_USER_FIXED
|
| FLAG_PERMISSION_USER_FIXED
|
||||||
@@ -19810,8 +19810,59 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED
|
final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED
|
||||||
| FLAG_PERMISSION_POLICY_FIXED;
|
| FLAG_PERMISSION_POLICY_FIXED;
|
||||||
|
|
||||||
boolean writeInstallPermissions = false;
|
// Delay and combine non-async permission callbacks
|
||||||
boolean writeRuntimePermissions = false;
|
final boolean[] permissionRemoved = new boolean[1];
|
||||||
|
final ArraySet<Long> revokedPermissions = new ArraySet<>();
|
||||||
|
final SparseBooleanArray updatedUsers = new SparseBooleanArray();
|
||||||
|
|
||||||
|
PermissionCallback delayingPermCallback = new PermissionCallback() {
|
||||||
|
public void onGidsChanged(int appId, int userId) {
|
||||||
|
mPermissionCallback.onGidsChanged(appId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPermissionChanged() {
|
||||||
|
mPermissionCallback.onPermissionChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPermissionGranted(int uid, int userId) {
|
||||||
|
mPermissionCallback.onPermissionGranted(uid, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onInstallPermissionGranted() {
|
||||||
|
mPermissionCallback.onInstallPermissionGranted();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPermissionRevoked(int uid, int userId) {
|
||||||
|
revokedPermissions.add(IntPair.of(uid, userId));
|
||||||
|
|
||||||
|
updatedUsers.put(userId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onInstallPermissionRevoked() {
|
||||||
|
mPermissionCallback.onInstallPermissionRevoked();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
|
||||||
|
for (int userId : updatedUserIds) {
|
||||||
|
if (sync) {
|
||||||
|
updatedUsers.put(userId, true);
|
||||||
|
} else {
|
||||||
|
// Don't override sync=true by sync=false
|
||||||
|
if (!updatedUsers.get(userId)) {
|
||||||
|
updatedUsers.put(userId, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPermissionRemoved() {
|
||||||
|
permissionRemoved[0] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onInstallPermissionUpdated() {
|
||||||
|
mPermissionCallback.onInstallPermissionUpdated();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
final int permissionCount = ps.pkg.requestedPermissions.size();
|
final int permissionCount = ps.pkg.requestedPermissions.size();
|
||||||
for (int i = 0; i < permissionCount; i++) {
|
for (int i = 0; i < permissionCount; i++) {
|
||||||
@@ -19843,26 +19894,20 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final PermissionsState permissionsState = ps.getPermissionsState();
|
final int oldFlags = mPermissionManager.getPermissionFlags(permName, packageName,
|
||||||
|
Process.SYSTEM_UID, userId);
|
||||||
final int oldFlags = permissionsState.getPermissionFlags(permName, userId);
|
|
||||||
|
|
||||||
// Always clear the user settable flags.
|
// Always clear the user settable flags.
|
||||||
final boolean hasInstallState =
|
|
||||||
permissionsState.getInstallPermissionState(permName) != null;
|
|
||||||
// If permission review is enabled and this is a legacy app, mark the
|
// If permission review is enabled and this is a legacy app, mark the
|
||||||
// permission as requiring a review as this is the initial state.
|
// permission as requiring a review as this is the initial state.
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) {
|
if (ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) {
|
||||||
flags |= FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
|
flags |= FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
|
||||||
}
|
}
|
||||||
if (permissionsState.updatePermissionFlags(bp, userId, userSettableMask, flags)) {
|
|
||||||
if (hasInstallState) {
|
mPermissionManager.updatePermissionFlags(permName, packageName,
|
||||||
writeInstallPermissions = true;
|
userSettableMask, flags, Process.SYSTEM_UID, userId, false,
|
||||||
} else {
|
delayingPermCallback);
|
||||||
writeRuntimePermissions = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Below is only runtime permission handling.
|
// Below is only runtime permission handling.
|
||||||
if (!bp.isRuntime()) {
|
if (!bp.isRuntime()) {
|
||||||
@@ -19876,35 +19921,42 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
|
|
||||||
// If this permission was granted by default, make sure it is.
|
// If this permission was granted by default, make sure it is.
|
||||||
if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
|
if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
|
||||||
if (permissionsState.grantRuntimePermission(bp, userId)
|
mPermissionManager.grantRuntimePermission(permName, packageName, false,
|
||||||
!= PERMISSION_OPERATION_FAILURE) {
|
Process.SYSTEM_UID, userId, delayingPermCallback);
|
||||||
writeRuntimePermissions = true;
|
|
||||||
}
|
|
||||||
// If permission review is enabled the permissions for a legacy apps
|
// If permission review is enabled the permissions for a legacy apps
|
||||||
// are represented as constantly granted runtime ones, so don't revoke.
|
// are represented as constantly granted runtime ones, so don't revoke.
|
||||||
} else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
|
} else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
|
||||||
// Otherwise, reset the permission.
|
// Otherwise, reset the permission.
|
||||||
final int revokeResult = permissionsState.revokeRuntimePermission(bp, userId);
|
mPermissionManager.revokeRuntimePermission(permName, packageName, false, userId,
|
||||||
switch (revokeResult) {
|
delayingPermCallback);
|
||||||
case PERMISSION_OPERATION_SUCCESS:
|
|
||||||
case PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
|
|
||||||
writeRuntimePermissions = true;
|
|
||||||
final int appId = ps.appId;
|
|
||||||
mHandler.post(
|
|
||||||
() -> killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED));
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synchronously write as we are taking permissions away.
|
// Execute delayed callbacks
|
||||||
if (writeRuntimePermissions) {
|
if (permissionRemoved[0]) {
|
||||||
mSettings.writeRuntimePermissionsForUserLPr(userId, true);
|
mPermissionCallback.onPermissionRemoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synchronously write as we are taking permissions away.
|
// Slight variation on the code in mPermissionCallback.onPermissionRevoked() as we cannot
|
||||||
if (writeInstallPermissions) {
|
// kill uid while holding mPackages-lock
|
||||||
mSettings.writeLPr();
|
if (!revokedPermissions.isEmpty()) {
|
||||||
|
int numRevokedPermissions = revokedPermissions.size();
|
||||||
|
for (int i = 0; i < numRevokedPermissions; i++) {
|
||||||
|
int revocationUID = IntPair.first(revokedPermissions.valueAt(i));
|
||||||
|
int revocationUserId = IntPair.second(revokedPermissions.valueAt(i));
|
||||||
|
|
||||||
|
mOnPermissionChangeListeners.onPermissionsChanged(revocationUID);
|
||||||
|
|
||||||
|
// Kill app later as we are holding mPackages
|
||||||
|
mHandler.post(() -> killUid(UserHandle.getAppId(revocationUID), revocationUserId,
|
||||||
|
KILL_APP_REASON_PERMISSIONS_REVOKED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int numUpdatedUsers = updatedUsers.size();
|
||||||
|
for (int i = 0; i < numUpdatedUsers; i++) {
|
||||||
|
mSettings.writeRuntimePermissionsForUserLPr(updatedUsers.keyAt(i),
|
||||||
|
updatedUsers.valueAt(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3126,6 +3126,27 @@ public class PermissionManagerService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtectionLevel(
|
||||||
|
@PermissionInfo.Protection int protectionLevel) {
|
||||||
|
ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
|
||||||
|
|
||||||
|
synchronized (PermissionManagerService.this.mLock) {
|
||||||
|
int numTotalPermissions = mSettings.mPermissions.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < numTotalPermissions; i++) {
|
||||||
|
BasePermission bp = mSettings.mPermissions.valueAt(i);
|
||||||
|
|
||||||
|
if (bp.perm != null && bp.perm.info != null
|
||||||
|
&& bp.protectionLevel == protectionLevel) {
|
||||||
|
matchingPermissions.add(bp.perm.info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchingPermissions;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
|
public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
|
||||||
return PermissionManagerService.this.backupRuntimePermissions(user);
|
return PermissionManagerService.this.backupRuntimePermissions(user);
|
||||||
|
|||||||
@@ -195,4 +195,8 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
|
|||||||
|
|
||||||
/** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
|
/** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
|
||||||
public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
|
public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
|
||||||
|
|
||||||
|
/** Get all permission that have a certain protection level */
|
||||||
|
public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtectionLevel(
|
||||||
|
@PermissionInfo.Protection int protectionLevel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import static android.app.AppOpsManager.MODE_FOREGROUND;
|
|||||||
import static android.app.AppOpsManager.MODE_IGNORED;
|
import static android.app.AppOpsManager.MODE_IGNORED;
|
||||||
import static android.app.AppOpsManager.OP_NONE;
|
import static android.app.AppOpsManager.OP_NONE;
|
||||||
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
|
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
|
||||||
|
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
|
||||||
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
@@ -41,20 +42,27 @@ import android.content.pm.PackageParser;
|
|||||||
import android.content.pm.PermissionInfo;
|
import android.content.pm.PermissionInfo;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceManager;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManagerInternal;
|
import android.os.UserManagerInternal;
|
||||||
import android.permission.PermissionControllerManager;
|
import android.permission.PermissionControllerManager;
|
||||||
import android.permission.PermissionManagerInternal;
|
|
||||||
import android.provider.Telephony;
|
import android.provider.Telephony;
|
||||||
import android.telecom.TelecomManager;
|
import android.telecom.TelecomManager;
|
||||||
|
import android.util.ArraySet;
|
||||||
|
import android.util.Pair;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseBooleanArray;
|
import android.util.SparseBooleanArray;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.app.IAppOpsCallback;
|
||||||
|
import com.android.internal.app.IAppOpsService;
|
||||||
|
import com.android.internal.util.function.pooled.PooledLambda;
|
||||||
import com.android.server.FgThread;
|
import com.android.server.FgThread;
|
||||||
import com.android.server.LocalServices;
|
import com.android.server.LocalServices;
|
||||||
import com.android.server.SystemService;
|
import com.android.server.SystemService;
|
||||||
|
import com.android.server.pm.permission.PermissionManagerServiceInternal;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
@@ -76,6 +84,13 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private final SparseBooleanArray mIsStarted = new SparseBooleanArray();
|
private final SparseBooleanArray mIsStarted = new SparseBooleanArray();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether an async {@link #synchronizePackagePermissionsAndAppOpsForUser} is currently
|
||||||
|
* scheduled for a package/user.
|
||||||
|
*/
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private final ArraySet<Pair<String, Integer>> mIsPackageSyncsScheduled = new ArraySet<>();
|
||||||
|
|
||||||
public PermissionPolicyService(@NonNull Context context) {
|
public PermissionPolicyService(@NonNull Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
@@ -86,8 +101,10 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
final PackageManagerInternal packageManagerInternal = LocalServices.getService(
|
final PackageManagerInternal packageManagerInternal = LocalServices.getService(
|
||||||
PackageManagerInternal.class);
|
PackageManagerInternal.class);
|
||||||
final PermissionManagerInternal permManagerInternal = LocalServices.getService(
|
final PermissionManagerServiceInternal permManagerInternal = LocalServices.getService(
|
||||||
PermissionManagerInternal.class);
|
PermissionManagerServiceInternal.class);
|
||||||
|
final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
|
||||||
|
ServiceManager.getService(Context.APP_OPS_SERVICE));
|
||||||
|
|
||||||
packageManagerInternal.getPackageList(new PackageListObserver() {
|
packageManagerInternal.getPackageList(new PackageListObserver() {
|
||||||
@Override
|
@Override
|
||||||
@@ -111,11 +128,62 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
permManagerInternal.addOnRuntimePermissionStateChangedListener(
|
permManagerInternal.addOnRuntimePermissionStateChangedListener(
|
||||||
(packageName, changedUserId) -> {
|
this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
|
||||||
if (isStarted(changedUserId)) {
|
|
||||||
synchronizePackagePermissionsAndAppOpsForUser(packageName, changedUserId);
|
IAppOpsCallback appOpsListener = new IAppOpsCallback.Stub() {
|
||||||
|
public void opChanged(int op, int uid, String packageName) {
|
||||||
|
synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName,
|
||||||
|
UserHandle.getUserId(uid));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final ArrayList<PermissionInfo> dangerousPerms =
|
||||||
|
permManagerInternal.getAllPermissionWithProtectionLevel(
|
||||||
|
PermissionInfo.PROTECTION_DANGEROUS);
|
||||||
|
|
||||||
|
try {
|
||||||
|
int numDangerousPerms = dangerousPerms.size();
|
||||||
|
for (int i = 0; i < numDangerousPerms; i++) {
|
||||||
|
PermissionInfo perm = dangerousPerms.get(i);
|
||||||
|
|
||||||
|
if (perm.isHardRestricted() || perm.backgroundPermission != null) {
|
||||||
|
appOpsService.startWatchingMode(AppOpsManager.permissionToOpCode(perm.name),
|
||||||
|
null, appOpsListener);
|
||||||
|
} else if (perm.isSoftRestricted()) {
|
||||||
|
appOpsService.startWatchingMode(AppOpsManager.permissionToOpCode(perm.name),
|
||||||
|
null, appOpsListener);
|
||||||
|
|
||||||
|
SoftRestrictedPermissionPolicy policy =
|
||||||
|
SoftRestrictedPermissionPolicy.forPermission(null, null, null,
|
||||||
|
perm.name);
|
||||||
|
if (policy.resolveAppOp() != OP_NONE) {
|
||||||
|
appOpsService.startWatchingMode(policy.resolveAppOp(), null,
|
||||||
|
appOpsListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (RemoteException doesNotHappen) {
|
||||||
|
Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void synchronizePackagePermissionsAndAppOpsAsyncForUser(@NonNull String packageName,
|
||||||
|
@UserIdInt int changedUserId) {
|
||||||
|
if (isStarted(changedUserId)) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) {
|
||||||
|
FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
|
||||||
|
PermissionPolicyService
|
||||||
|
::synchronizePackagePermissionsAndAppOpsForUser,
|
||||||
|
this, packageName, changedUserId));
|
||||||
|
} else {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.v(LOG_TAG, "sync for " + packageName + "/" + changedUserId
|
||||||
|
+ " already scheduled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -230,10 +298,14 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
*/
|
*/
|
||||||
private void synchronizePackagePermissionsAndAppOpsForUser(@NonNull String packageName,
|
private void synchronizePackagePermissionsAndAppOpsForUser(@NonNull String packageName,
|
||||||
@UserIdInt int userId) {
|
@UserIdInt int userId) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
mIsPackageSyncsScheduled.remove(new Pair<>(packageName, userId));
|
||||||
|
}
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.v(LOG_TAG,
|
Slog.v(LOG_TAG,
|
||||||
"synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", " + userId
|
"synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", "
|
||||||
+ ")");
|
+ userId + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
final PackageManagerInternal packageManagerInternal = LocalServices.getService(
|
final PackageManagerInternal packageManagerInternal = LocalServices.getService(
|
||||||
@@ -336,6 +408,16 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
*/
|
*/
|
||||||
private final @NonNull ArrayList<OpToUnrestrict> mOpsToForeground = new ArrayList<>();
|
private final @NonNull ArrayList<OpToUnrestrict> mOpsToForeground = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All ops that need to be flipped to foreground if allow.
|
||||||
|
*
|
||||||
|
* Currently, only used by the foreground/background permissions logic.
|
||||||
|
*
|
||||||
|
* @see #syncPackages
|
||||||
|
*/
|
||||||
|
private final @NonNull ArrayList<OpToUnrestrict> mOpsToForegroundIfAllow =
|
||||||
|
new ArrayList<>();
|
||||||
|
|
||||||
PermissionToOpSynchroniser(@NonNull Context context) {
|
PermissionToOpSynchroniser(@NonNull Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mPackageManager = context.getPackageManager();
|
mPackageManager = context.getPackageManager();
|
||||||
@@ -351,22 +433,27 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
final int allowCount = mOpsToAllow.size();
|
final int allowCount = mOpsToAllow.size();
|
||||||
for (int i = 0; i < allowCount; i++) {
|
for (int i = 0; i < allowCount; i++) {
|
||||||
final OpToUnrestrict op = mOpsToAllow.get(i);
|
final OpToUnrestrict op = mOpsToAllow.get(i);
|
||||||
setUidModeAllowed(op.code, op.uid);
|
setUidModeAllowed(op.code, op.uid, op.packageName);
|
||||||
}
|
}
|
||||||
final int allowIfDefaultCount = mOpsToAllowIfDefault.size();
|
final int allowIfDefaultCount = mOpsToAllowIfDefault.size();
|
||||||
for (int i = 0; i < allowIfDefaultCount; i++) {
|
for (int i = 0; i < allowIfDefaultCount; i++) {
|
||||||
final OpToUnrestrict op = mOpsToAllowIfDefault.get(i);
|
final OpToUnrestrict op = mOpsToAllowIfDefault.get(i);
|
||||||
setUidModeAllowedIfDefault(op.code, op.uid, op.packageName);
|
setUidModeAllowedIfDefault(op.code, op.uid, op.packageName);
|
||||||
}
|
}
|
||||||
final int foregroundCount = mOpsToForeground.size();
|
final int foregroundCount = mOpsToForegroundIfAllow.size();
|
||||||
for (int i = 0; i < foregroundCount; i++) {
|
for (int i = 0; i < foregroundCount; i++) {
|
||||||
|
final OpToUnrestrict op = mOpsToForegroundIfAllow.get(i);
|
||||||
|
setUidModeForegroundIfAllow(op.code, op.uid, op.packageName);
|
||||||
|
}
|
||||||
|
final int foregroundIfAllowCount = mOpsToForeground.size();
|
||||||
|
for (int i = 0; i < foregroundIfAllowCount; i++) {
|
||||||
final OpToUnrestrict op = mOpsToForeground.get(i);
|
final OpToUnrestrict op = mOpsToForeground.get(i);
|
||||||
setUidModeForeground(op.code, op.uid);
|
setUidModeForeground(op.code, op.uid, op.packageName);
|
||||||
}
|
}
|
||||||
final int ignoreCount = mOpsToIgnore.size();
|
final int ignoreCount = mOpsToIgnore.size();
|
||||||
for (int i = 0; i < ignoreCount; i++) {
|
for (int i = 0; i < ignoreCount; i++) {
|
||||||
final OpToUnrestrict op = mOpsToIgnore.get(i);
|
final OpToUnrestrict op = mOpsToIgnore.get(i);
|
||||||
setUidModeIgnored(op.code, op.uid);
|
setUidModeIgnored(op.code, op.uid, op.packageName);
|
||||||
}
|
}
|
||||||
final int ignoreIfDefaultCount = mOpsToIgnoreIfDefault.size();
|
final int ignoreIfDefaultCount = mOpsToIgnoreIfDefault.size();
|
||||||
for (int i = 0; i < ignoreIfDefaultCount; i++) {
|
for (int i = 0; i < ignoreIfDefaultCount; i++) {
|
||||||
@@ -459,6 +546,24 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isBgPermRestricted(@NonNull String pkg, @NonNull String perm, int uid) {
|
||||||
|
try {
|
||||||
|
final PermissionInfo bgPermInfo = mPackageManager.getPermissionInfo(perm, 0);
|
||||||
|
|
||||||
|
if (bgPermInfo.isSoftRestricted()) {
|
||||||
|
Slog.wtf(LOG_TAG, "Support for soft restricted background permissions not "
|
||||||
|
+ "implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
return bgPermInfo.isHardRestricted() && (mPackageManager.getPermissionFlags(
|
||||||
|
perm, pkg, UserHandle.getUserHandleForUid(uid))
|
||||||
|
& FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
|
||||||
|
} catch (NameNotFoundException e) {
|
||||||
|
Slog.w(LOG_TAG, "Cannot read permission state of " + perm, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add op that belong to a foreground permission for later processing in
|
* Add op that belong to a foreground permission for later processing in
|
||||||
* {@link #syncPackages()}.
|
* {@link #syncPackages()}.
|
||||||
@@ -481,26 +586,27 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
final String pkgName = pkg.packageName;
|
final String pkgName = pkg.packageName;
|
||||||
final int uid = pkg.applicationInfo.uid;
|
final int uid = pkg.applicationInfo.uid;
|
||||||
|
|
||||||
|
// App does not support runtime permissions. Hence the state is encoded in the app-op.
|
||||||
|
// To not override unrecoverable state don't change app-op unless bg perm is reviewed.
|
||||||
|
if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
|
||||||
|
// If the review is required for this permission, the grant state does not
|
||||||
|
// really matter. To have a stable state, don't change the app-op if review is still
|
||||||
|
// pending.
|
||||||
|
int flags = mPackageManager.getPermissionFlags(bgPermissionName,
|
||||||
|
pkg.packageName, UserHandle.getUserHandleForUid(uid));
|
||||||
|
|
||||||
|
if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0
|
||||||
|
&& isBgPermRestricted(pkgName, bgPermissionName, uid)) {
|
||||||
|
mOpsToForegroundIfAllow.add(new OpToUnrestrict(uid, pkgName, opCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mPackageManager.checkPermission(permission, pkgName)
|
if (mPackageManager.checkPermission(permission, pkgName)
|
||||||
== PackageManager.PERMISSION_GRANTED) {
|
== PackageManager.PERMISSION_GRANTED) {
|
||||||
boolean isBgHardRestricted = false;
|
final boolean isBgHardRestricted = isBgPermRestricted(pkgName, bgPermissionName,
|
||||||
try {
|
uid);
|
||||||
final PermissionInfo bgPermInfo = mPackageManager.getPermissionInfo(
|
|
||||||
bgPermissionName, 0);
|
|
||||||
|
|
||||||
if (bgPermInfo.isSoftRestricted()) {
|
|
||||||
Slog.wtf(LOG_TAG, "Support for soft restricted background permissions not "
|
|
||||||
+ "implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
isBgHardRestricted =
|
|
||||||
bgPermInfo.isHardRestricted() && (mPackageManager.getPermissionFlags(
|
|
||||||
bgPermissionName, pkgName, UserHandle.getUserHandleForUid(uid))
|
|
||||||
& FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
|
|
||||||
} catch (NameNotFoundException e) {
|
|
||||||
Slog.w(LOG_TAG, "Cannot read permission state of " + bgPermissionName, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean isBgPermGranted = mPackageManager.checkPermission(bgPermissionName,
|
final boolean isBgPermGranted = mPackageManager.checkPermission(bgPermissionName,
|
||||||
pkgName) == PackageManager.PERMISSION_GRANTED;
|
pkgName) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
|
||||||
@@ -554,42 +660,46 @@ public final class PermissionPolicyService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setUidModeAllowedIfDefault(int opCode, int uid, @NonNull String packageName) {
|
private void setUidModeAllowedIfDefault(int opCode, int uid, @NonNull String packageName) {
|
||||||
setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_ALLOWED, packageName);
|
setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_ALLOWED, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUidModeAllowed(int opCode, int uid) {
|
private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
|
||||||
mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED);
|
setUidMode(opCode, uid, MODE_ALLOWED, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUidModeForeground(int opCode, int uid) {
|
private void setUidModeForegroundIfAllow(int opCode, int uid, @NonNull String packageName) {
|
||||||
mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_FOREGROUND);
|
setUidModeIfMode(opCode, uid, MODE_ALLOWED, MODE_FOREGROUND, packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) {
|
||||||
|
setUidMode(opCode, uid, MODE_FOREGROUND, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUidModeIgnoredIfDefault(int opCode, int uid, @NonNull String packageName) {
|
private void setUidModeIgnoredIfDefault(int opCode, int uid, @NonNull String packageName) {
|
||||||
setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_IGNORED, packageName);
|
setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_IGNORED, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUidModeIgnored(int opCode, int uid) {
|
private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) {
|
||||||
mAppOpsManager.setUidMode(opCode, uid, MODE_IGNORED);
|
setUidMode(opCode, uid, MODE_IGNORED, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUidModeIfDefault(int opCode, int uid, int mode,
|
private void setUidMode(int opCode, int uid, int mode,
|
||||||
@NonNull String packageName) {
|
@NonNull String packageName) {
|
||||||
final int currentMode;
|
final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
|
||||||
try {
|
|
||||||
currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
|
|
||||||
.opToPublicName(opCode), uid, packageName);
|
.opToPublicName(opCode), uid, packageName);
|
||||||
} catch (SecurityException e) {
|
|
||||||
// This might happen if the app was uninstalled in between the add and sync step.
|
if (currentMode != mode) {
|
||||||
// In this case the package name cannot be resolved inside appops service and hence
|
mAppOpsManager.setUidMode(opCode, uid, mode);
|
||||||
// the uid does not match.
|
}
|
||||||
Slog.w(LOG_TAG, "Cannot set mode of uid=" + uid + " op=" + opCode + " to " + mode,
|
|
||||||
e);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentMode == MODE_DEFAULT) {
|
private void setUidModeIfMode(int opCode, int uid, int requiredModeBefore, int newMode,
|
||||||
mAppOpsManager.setUidMode(opCode, uid, mode);
|
@NonNull String packageName) {
|
||||||
|
final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
|
||||||
|
.opToPublicName(opCode), uid, packageName);
|
||||||
|
|
||||||
|
if (currentMode == requiredModeBefore) {
|
||||||
|
mAppOpsManager.setUidMode(opCode, uid, newMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYST
|
|||||||
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
|
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
@@ -75,14 +76,16 @@ public abstract class SoftRestrictedPermissionPolicy {
|
|||||||
* Get the policy for a soft restricted permission.
|
* Get the policy for a soft restricted permission.
|
||||||
*
|
*
|
||||||
* @param context A context to use
|
* @param context A context to use
|
||||||
* @param appInfo The application the permission belongs to
|
* @param appInfo The application the permission belongs to. Can be {@code null}, but then
|
||||||
* @param user The user the app belongs to
|
* only {@link #resolveAppOp} will work.
|
||||||
|
* @param user The user the app belongs to. Can be {@code null}, but then only
|
||||||
|
* {@link #resolveAppOp} will work.
|
||||||
* @param permission The name of the permission
|
* @param permission The name of the permission
|
||||||
*
|
*
|
||||||
* @return The policy for this permission
|
* @return The policy for this permission
|
||||||
*/
|
*/
|
||||||
public static @NonNull SoftRestrictedPermissionPolicy forPermission(@NonNull Context context,
|
public static @NonNull SoftRestrictedPermissionPolicy forPermission(@NonNull Context context,
|
||||||
@NonNull ApplicationInfo appInfo, @NonNull UserHandle user,
|
@Nullable ApplicationInfo appInfo, @Nullable UserHandle user,
|
||||||
@NonNull String permission) {
|
@NonNull String permission) {
|
||||||
switch (permission) {
|
switch (permission) {
|
||||||
// Storage uses a special app op to decide the mount state and supports soft restriction
|
// Storage uses a special app op to decide the mount state and supports soft restriction
|
||||||
@@ -90,13 +93,26 @@ public abstract class SoftRestrictedPermissionPolicy {
|
|||||||
// collections.
|
// collections.
|
||||||
case READ_EXTERNAL_STORAGE:
|
case READ_EXTERNAL_STORAGE:
|
||||||
case WRITE_EXTERNAL_STORAGE: {
|
case WRITE_EXTERNAL_STORAGE: {
|
||||||
int flags = context.getPackageManager().getPermissionFlags(
|
final int flags;
|
||||||
permission, appInfo.packageName, user);
|
final boolean applyRestriction;
|
||||||
boolean applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
|
final boolean isWhiteListed;
|
||||||
boolean isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
|
final boolean hasRequestedLegacyExternalStorage;
|
||||||
boolean hasRequestedLegacyExternalStorage =
|
final int targetSDK;
|
||||||
appInfo.hasRequestedLegacyExternalStorage();
|
|
||||||
int targetSDK = appInfo.targetSdkVersion;
|
if (appInfo != null) {
|
||||||
|
flags = context.getPackageManager().getPermissionFlags(permission,
|
||||||
|
appInfo.packageName, user);
|
||||||
|
applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
|
||||||
|
isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
|
||||||
|
hasRequestedLegacyExternalStorage = appInfo.hasRequestedLegacyExternalStorage();
|
||||||
|
targetSDK = appInfo.targetSdkVersion;
|
||||||
|
} else {
|
||||||
|
flags = 0;
|
||||||
|
applyRestriction = false;
|
||||||
|
isWhiteListed = false;
|
||||||
|
hasRequestedLegacyExternalStorage = false;
|
||||||
|
targetSDK = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return new SoftRestrictedPermissionPolicy() {
|
return new SoftRestrictedPermissionPolicy() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user