Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26a896ec authored by Philip P. Moltmann's avatar Philip P. Moltmann Committed by Android (Google) Code Review
Browse files

Merge "Set app-op for restricted pre-22 apps" into qt-dev

parents 0972aa6a 404b51c2
Loading
Loading
Loading
Loading
+125 −85
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.policy;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_ERRORED;
import static android.app.AppOpsManager.MODE_FOREGROUND;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_NONE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
@@ -290,7 +291,7 @@ public final class PermissionPolicyService extends SystemService {
         *
         * Currently, only used by the restricted permissions logic.
         *
         * @see #syncRestrictedOps
         * @see #syncPackages
         */
        private final @NonNull ArrayList<OpToRestrict> mOpsToDefault = new ArrayList<>();

@@ -299,16 +300,14 @@ public final class PermissionPolicyService extends SystemService {
         *
         * Currently, only used by the restricted permissions logic.
         *
         * @see #syncRestrictedOps
         * @see #syncPackages
         */
        private final @NonNull ArrayList<OpToUnrestrict> mOpsToAllowIfDefault = new ArrayList<>();

        /**
         * All ops that need to be flipped to allow.
         *
         * Currently, only used by the restricted permissions logic.
         *
         * @see #syncRestrictedOps
         * @see #syncPackages
         */
        private final @NonNull ArrayList<OpToUnrestrict> mOpsToAllow = new ArrayList<>();

@@ -317,16 +316,25 @@ public final class PermissionPolicyService extends SystemService {
         *
         * Currently, only used by the restricted permissions logic.
         *
         * @see #syncRestrictedOps
         * @see #syncPackages
         */
        private final @NonNull ArrayList<OpToUnrestrict> mOpsToIgnoreIfDefault = new ArrayList<>();

        /**
         * All foreground permissions
         * All ops that need to be flipped to ignore.
         *
         * @see #syncPackages
         */
        private final @NonNull ArrayList<OpToUnrestrict> mOpsToIgnore = new ArrayList<>();

        /**
         * All ops that need to be flipped to foreground.
         *
         * Currently, only used by the foreground/background permissions logic.
         *
         * @see #syncOpsOfFgPermissions()
         * @see #syncPackages
         */
        private final @NonNull ArrayList<FgPermission> mFgPermOps = new ArrayList<>();
        private final @NonNull ArrayList<OpToUnrestrict> mOpsToForeground = new ArrayList<>();

        PermissionToOpSynchroniser(@NonNull Context context) {
            mContext = context;
@@ -335,11 +343,11 @@ public final class PermissionPolicyService extends SystemService {
        }

        /**
         * Set app ops that belong to restricted permissions.
         * Set app ops that were added in {@link #addPackage}.
         *
         * <p>This processes ops previously added by {@link #addOpIfRestricted}
         */
        private void syncRestrictedOps() {
        private void syncPackages() {
            final int allowCount = mOpsToAllow.size();
            for (int i = 0; i < allowCount; i++) {
                final OpToUnrestrict op = mOpsToAllow.get(i);
@@ -350,6 +358,16 @@ public final class PermissionPolicyService extends SystemService {
                final OpToUnrestrict op = mOpsToAllowIfDefault.get(i);
                setUidModeAllowedIfDefault(op.code, op.uid, op.packageName);
            }
            final int foregroundCount = mOpsToForeground.size();
            for (int i = 0; i < foregroundCount; i++) {
                final OpToUnrestrict op = mOpsToForeground.get(i);
                setUidModeForeground(op.code, op.uid);
            }
            final int ignoreCount = mOpsToIgnore.size();
            for (int i = 0; i < ignoreCount; i++) {
                final OpToUnrestrict op = mOpsToIgnore.get(i);
                setUidModeIgnored(op.code, op.uid);
            }
            final int ignoreIfDefaultCount = mOpsToIgnoreIfDefault.size();
            for (int i = 0; i < ignoreIfDefaultCount; i++) {
                final OpToUnrestrict op = mOpsToIgnoreIfDefault.get(i);
@@ -362,47 +380,9 @@ public final class PermissionPolicyService extends SystemService {
            }
        }

        /**
         * Set app ops that belong to restricted permissions.
         *
         * <p>This processed ops previously added by {@link #addOpIfRestricted}
         */
        private void syncOpsOfFgPermissions() {
            int numFgPermOps = mFgPermOps.size();
            for (int i = 0; i < numFgPermOps; i++) {
                FgPermission perm = mFgPermOps.get(i);

                if (mPackageManager.checkPermission(perm.fgPermissionName, perm.packageName)
                        == PackageManager.PERMISSION_GRANTED) {
                    if (mPackageManager.checkPermission(perm.bgPermissionName, perm.packageName)
                            == PackageManager.PERMISSION_GRANTED) {
                        mAppOpsManager.setUidMode(
                                AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid,
                                AppOpsManager.MODE_ALLOWED);
                    } else {
                        mAppOpsManager.setUidMode(
                                AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid,
                                AppOpsManager.MODE_FOREGROUND);
                    }
                } else {
                    mAppOpsManager.setUidMode(
                            AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid,
                            AppOpsManager.MODE_IGNORED);
                }
            }
        }

        /**
         * Synchronize all previously {@link #addPackage added} packages.
         */
        void syncPackages() {
            syncRestrictedOps();
            syncOpsOfFgPermissions();
        }

        /**
         * Add op that belong to a restricted permission for later processing in
         * {@link #syncRestrictedOps}.
         * {@link #syncPackages()}.
         *
         * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
         *
@@ -424,19 +404,29 @@ public final class PermissionPolicyService extends SystemService {
                    mContext.getUser()) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;

            if (permissionInfo.isHardRestricted()) {
                if (opCode != OP_NONE) {
                    if (applyRestriction) {
                        mOpsToDefault.add(new OpToRestrict(uid, opCode));
                    } else {
                        mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode));
                    }
                }
            } else if (permissionInfo.isSoftRestricted()) {
                final SoftRestrictedPermissionPolicy policy =
                        SoftRestrictedPermissionPolicy.forPermission(mContext, pkg.applicationInfo,
                                permission);

                final int op = policy.getAppOp();
                if (opCode != OP_NONE) {
                    if (policy.canBeGranted()) {
                        mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode));
                    } else {
                        mOpsToDefault.add(new OpToRestrict(uid, opCode));
                    }
                }

                final int op = policy.resolveAppOp();
                if (op != OP_NONE) {
                    switch (policy.getAppOpMode()) {
                    switch (policy.getDesiredOpMode()) {
                        case MODE_DEFAULT:
                            mOpsToDefault.add(new OpToRestrict(uid, op));
                            break;
@@ -444,15 +434,21 @@ public final class PermissionPolicyService extends SystemService {
                            if (policy.shouldSetAppOpIfNotDefault()) {
                                mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName, op));
                            } else {
                                mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName,
                                mOpsToAllowIfDefault.add(
                                        new OpToUnrestrict(uid, pkg.packageName,
                                                op));
                            }
                            break;
                        case MODE_FOREGROUND:
                            Slog.wtf(LOG_TAG,
                                    "Setting appop to foreground is not implemented");
                            break;
                        case MODE_IGNORED:
                            if (policy.shouldSetAppOpIfNotDefault()) {
                                Slog.wtf(LOG_TAG, "Always ignoring appops is not implemented");
                                mOpsToIgnore.add(new OpToUnrestrict(uid, pkg.packageName, op));
                            } else {
                                mOpsToIgnoreIfDefault.add(new OpToUnrestrict(uid, pkg.packageName,
                                mOpsToIgnoreIfDefault.add(
                                        new OpToUnrestrict(uid, pkg.packageName,
                                                op));
                            }
                            break;
@@ -463,19 +459,59 @@ public final class PermissionPolicyService extends SystemService {
            }
        }

        /**
         * Add op that belong to a foreground permission for later processing in
         * {@link #syncPackages()}.
         *
         * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
         *
         * @param permissionInfo The permission that is currently looked at
         * @param pkg The package looked at
         */
        private void addOpIfFgPermissions(@NonNull PermissionInfo permissionInfo,
                @NonNull PackageInfo pkg) {
            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
                // Pre-M apps do not store their fg/bg state in the permissions
            final String bgPermissionName = permissionInfo.backgroundPermission;

            if (bgPermissionName == null) {
                return;
            }

            if (permissionInfo.backgroundPermission == null) {
                return;
            final String permission = permissionInfo.name;
            final int opCode = AppOpsManager.permissionToOpCode(permission);
            final String pkgName = pkg.packageName;
            final int uid = pkg.applicationInfo.uid;

            if (mPackageManager.checkPermission(permission, pkgName)
                    == PackageManager.PERMISSION_GRANTED) {
                boolean isBgHardRestricted = false;
                try {
                    final PermissionInfo bgPermInfo = mPackageManager.getPermissionInfo(
                            bgPermissionName, 0);

                    if (bgPermInfo.isSoftRestricted()) {
                        Slog.wtf(LOG_TAG, "Support for soft restricted background permissions not "
                                + "implemented");
                    }

            mFgPermOps.add(new FgPermission(pkg.applicationInfo.uid, pkg.packageName,
                    permissionInfo.name, permissionInfo.backgroundPermission));
                    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,
                        pkgName) == PackageManager.PERMISSION_GRANTED;

                if (!isBgHardRestricted && isBgPermGranted) {
                    mOpsToAllow.add(new OpToUnrestrict(uid, pkgName, opCode));
                } else {
                    mOpsToForeground.add(new OpToUnrestrict(uid, pkgName, opCode));
                }
            } else {
                mOpsToIgnore.add(new OpToUnrestrict(uid, pkgName, opCode));
            }
        }

        /**
@@ -525,14 +561,33 @@ public final class PermissionPolicyService extends SystemService {
            mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED);
        }

        private void setUidModeForeground(int opCode, int uid) {
            mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_FOREGROUND);
        }

        private void setUidModeIgnoredIfDefault(int opCode, int uid, @NonNull String packageName) {
            setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_IGNORED, packageName);
        }

        private void setUidModeIgnored(int opCode, int uid) {
            mAppOpsManager.setUidMode(opCode, uid, MODE_IGNORED);
        }

        private void setUidModeIfDefault(int opCode, int uid, int mode,
                @NonNull String packageName) {
            final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
            final int currentMode;
            try {
                currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
                        .opToPublicName(opCode), uid, packageName);
            } catch (SecurityException e) {
                // This might happen if the app was uninstalled in between the add and sync step.
                // In this case the package name cannot be resolved inside appops service and hence
                // 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) {
                mAppOpsManager.setUidMode(opCode, uid, mode);
            }
@@ -563,21 +618,6 @@ public final class PermissionPolicyService extends SystemService {
                this.code = code;
            }
        }

        private class FgPermission {
            final int uid;
            final @NonNull String packageName;
            final @NonNull String fgPermissionName;
            final @NonNull String bgPermissionName;

            private FgPermission(int uid, @NonNull String packageName,
                    @NonNull String fgPermissionName, @NonNull String bgPermissionName) {
                this.uid = uid;
                this.packageName = packageName;
                this.fgPermissionName = fgPermissionName;
                this.bgPermissionName = bgPermissionName;
            }
        }
    }

    private class Internal extends PermissionPolicyInternal {
+10 −17
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@ import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.util.Log;

/**
 * The behavior of soft restricted permissions is different for each permission. This class collects
@@ -43,8 +42,6 @@ import android.util.Log;
 * {@link com.android.packageinstaller.permission.utils.SoftRestrictedPermissionPolicy}
 */
public abstract class SoftRestrictedPermissionPolicy {
    private static final String LOG_TAG = SoftRestrictedPermissionPolicy.class.getSimpleName();

    private static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT =
            FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
                    | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
@@ -53,12 +50,12 @@ public abstract class SoftRestrictedPermissionPolicy {
    private static final SoftRestrictedPermissionPolicy DUMMY_POLICY =
            new SoftRestrictedPermissionPolicy() {
                @Override
                public int getAppOp() {
                public int resolveAppOp() {
                    return OP_NONE;
                }

                @Override
                public int getAppOpMode() {
                public int getDesiredOpMode() {
                    return MODE_DEFAULT;
                }

@@ -100,12 +97,12 @@ public abstract class SoftRestrictedPermissionPolicy {

                return new SoftRestrictedPermissionPolicy() {
                    @Override
                    public int getAppOp() {
                    public int resolveAppOp() {
                        return OP_LEGACY_STORAGE;
                    }

                    @Override
                    public int getAppOpMode() {
                    public int getDesiredOpMode() {
                        if (applyRestriction) {
                            return MODE_DEFAULT;
                        } else if (hasRequestedLegacyExternalStorage) {
@@ -119,7 +116,7 @@ public abstract class SoftRestrictedPermissionPolicy {
                    public boolean shouldSetAppOpIfNotDefault() {
                        // Do not switch from allowed -> ignored as this would mean to retroactively
                        // turn on isolated storage. This will make the app loose all its files.
                        return getAppOpMode() != MODE_IGNORED;
                        return getDesiredOpMode() != MODE_IGNORED;
                    }

                    @Override
@@ -127,10 +124,6 @@ public abstract class SoftRestrictedPermissionPolicy {
                        if (isWhiteListed || targetSDK >= Build.VERSION_CODES.Q) {
                            return true;
                        } else {
                            Log.w(LOG_TAG, permission + " for " + appInfo.packageName
                                    + " is not whitelisted and targetSDK " + targetSDK + "<"
                                    + Build.VERSION_CODES.Q);

                            return false;
                        }
                    }
@@ -145,16 +138,16 @@ public abstract class SoftRestrictedPermissionPolicy {
     * @return An app op to be changed based on the state of the permission or
     * {@link AppOpsManager#OP_NONE} if not app-op should be set.
     */
    public abstract int getAppOp();
    public abstract int resolveAppOp();

    /**
     * @return The mode the {@link #getAppOp() app op} should be in.
     * @return The mode the {@link #resolveAppOp() app op} should be in.
     */
    public abstract @AppOpsManager.Mode int getAppOpMode();
    public abstract @AppOpsManager.Mode int getDesiredOpMode();

    /**
     * @return If the {@link #getAppOp() app op} should be set even if the app-op is currently not
     * {@link AppOpsManager#MODE_DEFAULT}.
     * @return If the {@link #resolveAppOp() app op} should be set even if the app-op is currently
     * not {@link AppOpsManager#MODE_DEFAULT}.
     */
    public abstract boolean shouldSetAppOpIfNotDefault();

+8 −0
Original line number Diff line number Diff line
@@ -35,6 +35,14 @@
          "include-filter": "android.permission2.cts.RestrictedPermissionsTest"
        }
      ]
    },
    {
      "name": "CtsPermissionTestCases",
      "options": [
        {
          "include-filter": "android.permission.cts.SplitPermissionTest"
        }
      ]
    }
  ],
  "postsubmit": [