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

Commit 17f65afe authored by Philip P. Moltmann's avatar Philip P. Moltmann
Browse files

Split permissions inherit state from their parents

The old hack to grant permissions on upgrade was removed. The new code
applies to
- platfrom upgrade
- initial package installation
- package update

Inheriting the grant state is the default behavior for split permissions.
Special cases will be added later.

Also make sure to revoke the permission once the app declares that it is
aware of the permission.

Test: atest CtsPermissionTestCases:SplitPermissionTest
Change-Id: Ie51971530607f0b585cf7a3e11b01b11a28e1de9
parent e1b277a4
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.app;

import android.annotation.NonNull;
import android.util.SparseIntArray;

import com.android.internal.util.function.QuadFunction;
@@ -73,4 +74,21 @@ public abstract class AppOpsManagerInternal {
     * access to app ops for their user.
     */
    public abstract void setDeviceAndProfileOwners(SparseIntArray owners);

    /**
     * Sets the app-ops mode for a certain app-op and uid.
     *
     * <p>Similar as {@link AppOpsManager#setMode} but does not require the package manager to be
     * working. Hence this can be used very early during boot.
     *
     * <p>Only for internal callers. Does <u>not</u> verify that package name belongs to uid.
     *
     * @param code The op code to set.
     * @param uid The UID for which to set.
     * @param packageName The package for which to set.
     * @param mode The new mode to set.
     * @param isPrivileged If the package is privileged
     */
    public abstract void setMode(int code, int uid, @NonNull String packageName, int mode,
            boolean isPrivileged);
}
+14 −1
Original line number Diff line number Diff line
@@ -2942,6 +2942,15 @@ public abstract class PackageManager {
    @SystemApi
    public static final int FLAG_PERMISSION_REVIEW_REQUIRED =  1 << 6;

    /**
     * Permission flag: The permission has not been explicitly requested by
     * the app but has been added automatically by the system. Revoke once
     * the app does explicitly request it.
     *
     * @hide
     */
    public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED =  1 << 7;

    /**
     * Mask for all permission flags.
     *
@@ -3593,7 +3602,10 @@ public abstract class PackageManager {
            FLAG_PERMISSION_POLICY_FIXED,
            FLAG_PERMISSION_REVOKE_ON_UPGRADE,
            FLAG_PERMISSION_SYSTEM_FIXED,
            FLAG_PERMISSION_GRANTED_BY_DEFAULT
            FLAG_PERMISSION_GRANTED_BY_DEFAULT,
            /*
            FLAG_PERMISSION_REVOKE_WHEN_REQUESED
            */
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface PermissionFlags {}
@@ -6133,6 +6145,7 @@ public abstract class PackageManager {
            case FLAG_PERMISSION_REVOKE_ON_UPGRADE: return "REVOKE_ON_UPGRADE";
            case FLAG_PERMISSION_USER_FIXED: return "USER_FIXED";
            case FLAG_PERMISSION_REVIEW_REQUIRED: return "REVIEW_REQUIRED";
            case FLAG_PERMISSION_REVOKE_WHEN_REQUESTED: return "REVOKE_WHEN_REQUESTED";
            default: return Integer.toString(flag);
        }
    }
+17 −9
Original line number Diff line number Diff line
@@ -2435,7 +2435,7 @@ public class PackageParser {
        }

        final int NP = PackageParser.NEW_PERMISSIONS.length;
        StringBuilder implicitPerms = null;
        StringBuilder newPermsMsg = null;
        for (int ip=0; ip<NP; ip++) {
            final PackageParser.NewPermissionInfo npi
                    = PackageParser.NEW_PERMISSIONS[ip];
@@ -2443,19 +2443,20 @@ public class PackageParser {
                break;
            }
            if (!pkg.requestedPermissions.contains(npi.name)) {
                if (implicitPerms == null) {
                    implicitPerms = new StringBuilder(128);
                    implicitPerms.append(pkg.packageName);
                    implicitPerms.append(": compat added ");
                if (newPermsMsg == null) {
                    newPermsMsg = new StringBuilder(128);
                    newPermsMsg.append(pkg.packageName);
                    newPermsMsg.append(": compat added ");
                } else {
                    implicitPerms.append(' ');
                    newPermsMsg.append(' ');
                }
                implicitPerms.append(npi.name);
                newPermsMsg.append(npi.name);
                pkg.requestedPermissions.add(npi.name);
                pkg.implicitPermissions.add(npi.name);
            }
        }
        if (implicitPerms != null) {
            Slog.i(TAG, implicitPerms.toString());
        if (newPermsMsg != null) {
            Slog.i(TAG, newPermsMsg.toString());
        }


@@ -2472,6 +2473,7 @@ public class PackageParser {
                final String perm = newPerms.get(in);
                if (!pkg.requestedPermissions.contains(perm)) {
                    pkg.requestedPermissions.add(perm);
                    pkg.implicitPermissions.add(perm);
                }
            }
        }
@@ -6394,6 +6396,9 @@ public class PackageParser {
        @UnsupportedAppUsage
        public final ArrayList<String> requestedPermissions = new ArrayList<String>();

        /** Permissions requested but not in the manifest. */
        public final ArrayList<String> implicitPermissions = new ArrayList<>();

        @UnsupportedAppUsage
        public ArrayList<String> protectedBroadcasts;

@@ -6923,6 +6928,8 @@ public class PackageParser {

            dest.readStringList(requestedPermissions);
            internStringArrayList(requestedPermissions);
            dest.readStringList(implicitPermissions);
            internStringArrayList(implicitPermissions);
            protectedBroadcasts = dest.createStringArrayList();
            internStringArrayList(protectedBroadcasts);

@@ -7087,6 +7094,7 @@ public class PackageParser {
            dest.writeParcelableList(instrumentation, flags);

            dest.writeStringList(requestedPermissions);
            dest.writeStringList(implicitPermissions);
            dest.writeStringList(protectedBroadcasts);

            // TODO: This doesn't work: b/64295061
+85 −6
Original line number Diff line number Diff line
@@ -1210,13 +1210,29 @@ public class AppOpsService extends IAppOpsService.Stub {

    @Override
    public void setMode(int code, int uid, String packageName, int mode) {
        setMode(code, uid, packageName, mode, true, false);
    }

    /**
     * Sets the mode for a certain op and uid.
     *
     * @param code The op code to set
     * @param uid The UID for which to set
     * @param packageName The package for which to set
     * @param mode The new mode to set
     * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
     * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
     *                     false})
     */
    private void setMode(int code, int uid, @NonNull String packageName, int mode,
            boolean verifyUid, boolean isPrivileged) {
        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
        verifyIncomingOp(code);
        ArraySet<ModeCallback> repCbs = null;
        code = AppOpsManager.opToSwitch(code);
        synchronized (this) {
            UidState uidState = getUidStateLocked(uid, false);
            Op op = getOpLocked(code, uid, packageName, true);
            Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
            if (op != null) {
                if (op.mode != mode) {
                    op.mode = mode;
@@ -1575,7 +1591,7 @@ public class AppOpsService extends IAppOpsService.Stub {
                    && uidState.opModes.indexOfKey(code) >= 0) {
                return uidState.opModes.get(code);
            }
            Op op = getOpLocked(code, uid, resolvedPackageName, false);
            Op op = getOpLocked(code, uid, resolvedPackageName, false, true, false);
            if (op == null) {
                return AppOpsManager.opToDefaultMode(code);
            }
@@ -1918,7 +1934,7 @@ public class AppOpsService extends IAppOpsService.Stub {
        }
        ClientState client = (ClientState) token;
        synchronized (this) {
            Op op = getOpLocked(code, uid, resolvedPackageName, true);
            Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
            if (op == null) {
                return;
            }
@@ -2172,6 +2188,43 @@ public class AppOpsService extends IAppOpsService.Stub {
        return ops;
    }

    /**
     * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>.
     *
     * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
     *
     * @param uid The uid the of the package
     * @param packageName The package name for which to get the state for
     * @param edit Iff {@code true} create the {@link Ops} object if not yet created
     * @param isPrivileged Whether the package is privileged or not
     *
     * @return The {@link Ops state} of all ops for the package
     */
    private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
            boolean edit, boolean isPrivileged) {
        UidState uidState = getUidStateLocked(uid, edit);
        if (uidState == null) {
            return null;
        }

        if (uidState.pkgOps == null) {
            if (!edit) {
                return null;
            }
            uidState.pkgOps = new ArrayMap<>();
        }

        Ops ops = uidState.pkgOps.get(packageName);
        if (ops == null) {
            if (!edit) {
                return null;
            }
            ops = new Ops(packageName, uidState, isPrivileged);
            uidState.pkgOps.put(packageName, ops);
        }
        return ops;
    }

    private void scheduleWriteLocked() {
        if (!mWriteScheduled) {
            mWriteScheduled = true;
@@ -2188,9 +2241,29 @@ public class AppOpsService extends IAppOpsService.Stub {
        }
    }

    private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
        Ops ops = getOpsRawLocked(uid, packageName, edit,
                false /* uidMismatchExpected */);
    /**
     * Get the state of an op for a uid.
     *
     * @param code The code of the op
     * @param uid The uid the of the package
     * @param packageName The package name for which to get the state for
     * @param edit Iff {@code true} create the {@link Op} object if not yet created
     * @param verifyUid Iff {@code true} check that the package belongs to the uid
     * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
     *                     == false})
     *
     * @return The {@link Op state} of the op
     */
    private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
            boolean verifyUid, boolean isPrivileged) {
        Ops ops;

        if (verifyUid) {
            ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
        }  else {
            ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
        }

        if (ops == null) {
            return null;
        }
@@ -3948,5 +4021,11 @@ public class AppOpsService extends IAppOpsService.Stub {
                mProfileOwners = owners;
            }
        }

        @Override
        public void setMode(int code, int uid, @NonNull String packageName, int mode,
                boolean isPrivileged) {
            AppOpsService.this.setMode(code, uid, packageName, mode, false, isPrivileged);
        }
    }
}
+0 −55
Original line number Diff line number Diff line
@@ -239,7 +239,6 @@ import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.permission.PermissionManager;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.security.KeyStore;
@@ -2930,60 +2929,6 @@ public class PackageManagerService extends IPackageManager.Stub
            checkDefaultBrowser();
            // If a granted permission is split, all new permissions should be granted too
            if (mIsUpgrade) {
                final int callingUid = getCallingUid();
                final List<PermissionManager.SplitPermissionInfo> splitPermissions =
                        mContext.getSystemService(PermissionManager.class).getSplitPermissions();
                final int numSplitPerms = splitPermissions.size();
                for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
                    final PermissionManager.SplitPermissionInfo splitPerm =
                            splitPermissions.get(splitPermNum);
                    final String rootPerm = splitPerm.getSplitPermission();
                    if (preUpgradeSdkVersion >= splitPerm.getTargetSdk()) {
                        continue;
                    }
                    final int numPackages = mPackages.size();
                    for (int packageNum = 0; packageNum < numPackages; packageNum++) {
                        final PackageParser.Package pkg = mPackages.valueAt(packageNum);
                        if (pkg.applicationInfo.targetSdkVersion >= splitPerm.getTargetSdk()
                                || !pkg.requestedPermissions.contains(rootPerm)) {
                            continue;
                        }
                        final int userId = UserHandle.getUserId(pkg.applicationInfo.uid);
                        final String pkgName = pkg.packageName;
                        if (checkPermission(rootPerm, pkgName, userId) == PERMISSION_DENIED) {
                            continue;
                        }
                        final List<String> newPerms = splitPerm.getNewPermissions();
                        final int numNewPerms = newPerms.size();
                        for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
                            final String newPerm = newPerms.get(newPermNum);
                            if (checkPermission(newPerm, pkgName, userId) == PERMISSION_GRANTED) {
                                continue;
                            }
                            if (DEBUG_PERMISSIONS) {
                                Slog.v(TAG, "Granting " + newPerm + " to " + pkgName
                                        + " as the root permission " + rootPerm
                                        + " is already granted");
                            }
                            mPermissionManager.grantRuntimePermission(newPerm, pkgName, true,
                                    callingUid, userId, null);
                        }
                    }
                }
            }
            // clear only after permissions and other defaults have been updated
            mExistingSystemPackages.clear();
            mPromoteSystemApps = false;
Loading