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

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

Merge "Revert "Make PermPolicySvc based on uid""

parents 3899bdc8 f9486608
Loading
Loading
Loading
Loading
+95 −125
Original line number Diff line number Diff line
@@ -39,7 +39,9 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PermissionInfo;
import android.content.pm.parsing.AndroidPackage;
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -50,15 +52,14 @@ import android.telecom.TelecomManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongSparseLongArray;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IntPair;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
@@ -69,7 +70,6 @@ import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;

/**
@@ -100,7 +100,7 @@ public final class PermissionPolicyService extends SystemService {
     * scheduled for a package/user.
     */
    @GuardedBy("mLock")
    private final ArraySet<Integer> mIsPackageSyncsScheduled = new ArraySet<>();
    private final ArraySet<Pair<String, Integer>> mIsPackageSyncsScheduled = new ArraySet<>();

    public PermissionPolicyService(@NonNull Context context) {
        super(context);
@@ -125,8 +125,10 @@ public final class PermissionPolicyService extends SystemService {

            @Override
            public void onPackageChanged(String packageName, int uid) {
                if (isStarted(UserHandle.getUserId(uid))) {
                    synchronizePackagePermissionsAndAppOpsForUser(uid);
                final int userId = UserHandle.getUserId(uid);

                if (isStarted(userId)) {
                    synchronizePackagePermissionsAndAppOpsForUser(packageName, userId);
                }
            }

@@ -137,21 +139,12 @@ public final class PermissionPolicyService extends SystemService {
        });

        permManagerInternal.addOnRuntimePermissionStateChangedListener(
                (packageName, userId) -> {
                    int uid;
                    try {
                        uid = getContext().getPackageManager().getPackageUidAsUser(packageName, 0,
                                userId);
                    } catch (NameNotFoundException e) {
                        Slog.e(LOG_TAG, "Cannot synchronize changed package " + packageName, e);
                        return;
                    }
                    synchronizeUidPermissionsAndAppOpsAsync(uid);
                });
                this::synchronizePackagePermissionsAndAppOpsAsyncForUser);

        mAppOpsCallback = new IAppOpsCallback.Stub() {
            public void opChanged(int op, int uid, String packageName) {
                synchronizeUidPermissionsAndAppOpsAsync(uid);
                synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName,
                        UserHandle.getUserId(uid));
            }
        };

@@ -201,17 +194,19 @@ public final class PermissionPolicyService extends SystemService {
        return AppOpsManager.opToSwitch(op);
    }

    private void synchronizeUidPermissionsAndAppOpsAsync(int uid) {
        if (isStarted(UserHandle.getUserId(uid))) {
    private void synchronizePackagePermissionsAndAppOpsAsyncForUser(@NonNull String packageName,
            @UserIdInt int changedUserId) {
        if (isStarted(changedUserId)) {
            synchronized (mLock) {
                if (mIsPackageSyncsScheduled.add(uid)) {
                if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) {
                    FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
                            PermissionPolicyService
                                    ::synchronizePackagePermissionsAndAppOpsForUser,
                            this, uid));
                            this, packageName, changedUserId));
                } else {
                    if (DEBUG) {
                        Slog.v(LOG_TAG, "sync for " + uid + " already scheduled");
                        Slog.v(LOG_TAG, "sync for " + packageName + "/" + changedUserId
                                + " already scheduled");
                    }
                }
            }
@@ -340,20 +335,39 @@ public final class PermissionPolicyService extends SystemService {
    /**
     * Synchronize a single package.
     */
    private void synchronizePackagePermissionsAndAppOpsForUser(int uid) {
    private void synchronizePackagePermissionsAndAppOpsForUser(@NonNull String packageName,
            @UserIdInt int userId) {
        synchronized (mLock) {
            mIsPackageSyncsScheduled.remove(uid);
            mIsPackageSyncsScheduled.remove(new Pair<>(packageName, userId));
        }

        if (DEBUG) {
            Slog.v(LOG_TAG,
                    "synchronizePackagePermissionsAndAppOpsForUser(" + uid + ")");
                    "synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", "
                            + userId + ")");
        }

        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
                PackageManagerInternal.class);
        final PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName, 0,
                Process.SYSTEM_UID, userId);
        if (pkg == null) {
            return;
        }
        final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(
                getUserContext(getContext(), UserHandle.getUserHandleForUid(uid)));
        synchroniser.addUid(uid);
        synchroniser.syncUids();
                getUserContext(getContext(), UserHandle.of(userId)));
        synchroniser.addPackage(pkg.packageName);
        final String[] sharedPkgNames = packageManagerInternal.getSharedUserPackagesForPackage(
                pkg.packageName, userId);

        for (String sharedPkgName : sharedPkgNames) {
            final AndroidPackage sharedPkg = packageManagerInternal
                    .getPackage(sharedPkgName);
            if (sharedPkg != null) {
                synchroniser.addPackage(sharedPkg.getPackageName());
            }
        }
        synchroniser.syncPackages();
    }

    /**
@@ -367,8 +381,8 @@ public final class PermissionPolicyService extends SystemService {
        final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(
                getUserContext(getContext(), UserHandle.of(userId)));
        packageManagerInternal.forEachPackage(
                (pkg) -> synchronizer.addUid(pkg.getUid()));
        synchronizer.syncUids();
                (pkg) -> synchronizer.addPackage(pkg.getPackageName()));
        synchronizer.syncPackages();
    }

    /**
@@ -383,51 +397,37 @@ public final class PermissionPolicyService extends SystemService {

        private final @NonNull ArrayMap<String, PermissionInfo> mRuntimePermissionInfos;

        // Cache uid -> packageNames
        private SparseArray<String[]> mUidToPkg = new SparseArray<>();

        /**
         * All ops that need to be flipped to allow.
         *
         * @see #syncUids
         * @see #syncPackages
         */
        private final @NonNull ArraySet<OpToChange> mOpsToAllow = new ArraySet<>();
        private final @NonNull ArrayList<OpToChange> mOpsToAllow = new ArrayList<>();

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

        /**
         * All ops that need to be flipped to ignore if not allowed.
         *
         * Currently, only used by soft restricted permissions logic.
         *
         * @see #syncUids
         * @see #syncPackages
         */
        private final @NonNull ArraySet<OpToChange> mOpsToIgnoreIfNotAllowed = new ArraySet<>();
        private final @NonNull ArrayList<OpToChange> mOpsToIgnoreIfNotAllowed = new ArrayList<>();

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

        private @Nullable String[] getPackageNamesForUid(int uid) {
            String[] pkgs = mUidToPkg.get(uid);
            if (pkgs != null) {
                return pkgs;
            }

            pkgs = mPackageManager.getPackagesForUid(uid);
            mUidToPkg.put(uid, pkgs);
            return pkgs;
        }
        private final @NonNull ArrayList<OpToChange> mOpsToForeground = new ArrayList<>();

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

        /**
         * Set app ops that were added in {@link #addUid}.
         * Set app ops that were added in {@link #addPackage}.
         *
         * <p>This processes ops previously added by {@link #addAppOps(PackageInfo, String)}
         */
        private void syncUids() {
        private void syncPackages() {
            // Remember which ops were already set. This makes sure that we always set the most
            // permissive mode if two OpChanges are scheduled. This can e.g. happen if two
            // permissions change the same op. See {@link #getSwitchOp}.
@@ -461,42 +461,42 @@ public final class PermissionPolicyService extends SystemService {

            final int allowCount = mOpsToAllow.size();
            for (int i = 0; i < allowCount; i++) {
                final OpToChange op = mOpsToAllow.valueAt(i);
                final OpToChange op = mOpsToAllow.get(i);

                setUidModeAllowed(op.code, op.uid);
                setUidModeAllowed(op.code, op.uid, op.packageName);
                alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
            }

            final int foregroundCount = mOpsToForeground.size();
            for (int i = 0; i < foregroundCount; i++) {
                final OpToChange op = mOpsToForeground.valueAt(i);
                final OpToChange op = mOpsToForeground.get(i);
                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
                    continue;
                }

                setUidModeForeground(op.code, op.uid);
                setUidModeForeground(op.code, op.uid, op.packageName);
                alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
            }

            final int ignoreCount = mOpsToIgnore.size();
            for (int i = 0; i < ignoreCount; i++) {
                final OpToChange op = mOpsToIgnore.valueAt(i);
                final OpToChange op = mOpsToIgnore.get(i);
                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
                    continue;
                }

                setUidModeIgnored(op.code, op.uid);
                setUidModeIgnored(op.code, op.uid, op.packageName);
                alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
            }

            final int ignoreIfNotAllowedCount = mOpsToIgnoreIfNotAllowed.size();
            for (int i = 0; i < ignoreIfNotAllowedCount; i++) {
                final OpToChange op = mOpsToIgnoreIfNotAllowed.valueAt(i);
                final OpToChange op = mOpsToIgnoreIfNotAllowed.get(i);
                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
                    continue;
                }

                boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid);
                boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid, op.packageName);
                if (wasSet) {
                    alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
                }
@@ -555,7 +555,7 @@ public final class PermissionPolicyService extends SystemService {
            }

            int uid = packageInfo.applicationInfo.uid;
            OpToChange opToChange = new OpToChange(uid, appOpCode);
            OpToChange opToChange = new OpToChange(uid, packageName, appOpCode);
            switch (appOpMode) {
                case MODE_ALLOWED:
                    mOpsToAllow.add(opToChange);
@@ -618,7 +618,8 @@ public final class PermissionPolicyService extends SystemService {
            }

            int uid = packageInfo.applicationInfo.uid;
            OpToChange extraOpToChange = new OpToChange(uid, extraOpCode);
            String packageName = packageInfo.packageName;
            OpToChange extraOpToChange = new OpToChange(uid, packageName, extraOpCode);
            if (policy.mayAllowExtraAppOp()) {
                mOpsToAllow.add(extraOpToChange);
            } else {
@@ -631,56 +632,45 @@ public final class PermissionPolicyService extends SystemService {
        }

        /**
         * Add a Uid for {@link #syncUids() processing} later.
         * Add a package for {@link #syncPackages() processing} later.
         *
         * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
         *
         * @param uid The uid to add for later processing.
         * @param pkgName The package to add for later processing.
         */
        void addUid(int uid) {
            String[] pkgNames = getPackageNamesForUid(uid);
            if (pkgNames == null) {
                return;
            }

            for (String pkgName : pkgNames) {
        void addPackage(@NonNull String pkgName) {
            final PackageInfo pkg;
            try {
                pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS);
            } catch (NameNotFoundException e) {
                    continue;
                return;
            }

            if (pkg.requestedPermissions == null) {
                    continue;
                return;
            }

            for (String permission : pkg.requestedPermissions) {
                addAppOps(pkg, permission);
            }
        }
        }

        private void setUidModeAllowed(int opCode, int uid) {
            setUidMode(opCode, uid, MODE_ALLOWED);
        private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
            setUidMode(opCode, uid, MODE_ALLOWED, packageName);
        }

        private void setUidModeForeground(int opCode, int uid) {
            setUidMode(opCode, uid, MODE_FOREGROUND);
        private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) {
            setUidMode(opCode, uid, MODE_FOREGROUND, packageName);
        }

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

        private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid) {
            String[] pkgsOfUid = getPackageNamesForUid(uid);
            if (ArrayUtils.isEmpty(pkgsOfUid)) {
                return false;
        private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) {
            setUidMode(opCode, uid, MODE_IGNORED, packageName);
        }

        private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid,
                @NonNull String packageName) {
            final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
                    opCode), uid, pkgsOfUid[0]);
                    opCode), uid, packageName);
            if (currentMode != MODE_ALLOWED) {
                if (currentMode != MODE_IGNORED) {
                    mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, MODE_IGNORED,
@@ -691,24 +681,20 @@ public final class PermissionPolicyService extends SystemService {
            return false;
        }

        private void setUidMode(int opCode, int uid, int mode) {
            String[] pkgsOfUid = getPackageNamesForUid(uid);
            if (ArrayUtils.isEmpty(pkgsOfUid)) {
                return;
            }

        private void setUidMode(int opCode, int uid, int mode,
                @NonNull String packageName) {
            final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
                    opCode), uid, pkgsOfUid[0]);
                    opCode), uid, packageName);
            if (oldMode != mode) {
                mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, mode,
                        mAppOpsCallback);
                final int newMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
                        opCode), uid, pkgsOfUid[0]);
                        opCode), uid, packageName);
                if (newMode != mode) {
                    // Work around incorrectly-set package mode. It never makes sense for app ops
                    // related to runtime permissions, but can get in the way and we have to reset
                    // it.
                    mAppOpsManagerInternal.setModeFromPermissionPolicy(opCode, uid, pkgsOfUid[0],
                    mAppOpsManagerInternal.setModeFromPermissionPolicy(opCode, uid, packageName,
                            AppOpsManager.opToDefaultMode(opCode), mAppOpsCallback);
                }
            }
@@ -716,30 +702,14 @@ public final class PermissionPolicyService extends SystemService {

        private class OpToChange {
            final int uid;
            final @NonNull String packageName;
            final int code;

            OpToChange(int uid, int code) {
            OpToChange(int uid, @NonNull String packageName, int code) {
                this.uid = uid;
                this.packageName = packageName;
                this.code = code;
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) {
                    return true;
                }
                if (o == null || getClass() != o.getClass()) {
                    return false;
                }

                OpToChange other = (OpToChange) o;
                return uid == other.uid && code == other.code;
            }

            @Override
            public int hashCode() {
                return Objects.hash(uid, code);
            }
        }
    }