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

Commit 4583da1a authored by Hai Zhang's avatar Hai Zhang
Browse files

Split PermissionSettings into LegacyPermissionSettings and PermissionRegistry.

And split BasePermission into LegacyPermission and Permission.

This way permission definitions become independent from package
manager settings which enables using its own locking. The legacy
classes are only for reading, compat dumping, and temporary writing
before we migrate persistence.

Similar to how we handled permission state, we are not migrating the
persistence in this change, but writing back to the legacy class for
persistence.

The BasePermission reference is removed in LegacyPermissionState, as
having only the permission name is already sufficient.

The "requested permissions" section in dump no longer prints whether a
the requested permission is restricted - the info is still available
in the permissions section.

Bug: 168319670
Test: manual
Change-Id: Ieac5f4005f6f04dde4a88592dec534f31f298624
parent 0295b66b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -918,7 +918,7 @@ class InstantAppRegistry {
        try {
            for (String grantedPermission : appInfo.getGrantedPermissions()) {
                final boolean propagatePermission =
                        mService.mSettings.canPropagatePermissionToInstantApp(grantedPermission);
                        mPermissionManager.canPropagatePermissionToInstantApp(grantedPermission);
                if (propagatePermission && pkg.getRequestedPermissions().contains(
                        grantedPermission)) {
                    mService.grantRuntimePermission(pkg.getPackageName(), grantedPermission,
+12 −10
Original line number Diff line number Diff line
@@ -375,7 +375,7 @@ import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.Permission;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.policy.PermissionPolicyInternal;
@@ -2742,7 +2742,6 @@ public class PackageManagerService extends IPackageManager.Stub
                        new UserDataPreparer(installer, installLock, context, onlyCore),
                        lock),
                (i, pm) -> new Settings(Environment.getDataDirectory(),
                        i.getPermissionManagerServiceInternal().getPermissionSettings(),
                        RuntimePermissionsPersistence.createInstance(),
                        i.getPermissionManagerServiceInternal(), lock),
                (i, pm) -> AppsFilter.create(pm.mPmInternal, i),
@@ -3173,6 +3172,8 @@ public class PackageManagerService extends IPackageManager.Stub
                    /* excludePreCreated= */ false));
            t.traceEnd();
            mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions);
            // Clean up orphaned packages for which the code path doesn't exist
            // and they are an update to a system app - caused by bug/32321269
            final int packageSettingCount = mSettings.mPackages.size();
@@ -3597,7 +3598,7 @@ public class PackageManagerService extends IPackageManager.Stub
                    + ((SystemClock.uptimeMillis()-startTime)/1000f)
                    + " seconds");
            mPermissionManager.readStateFromPackageSettingsTEMP();
            mPermissionManager.readLegacyPermissionStateTEMP();
            // If the platform SDK has changed since the last time we booted,
            // we need to re-grant app permission to catch any new ones that
            // appear.  This is really a hack, and means that apps can in some
@@ -11433,7 +11434,7 @@ public class PackageManagerService extends IPackageManager.Stub
                    if (verifyPackageUpdateLPr(orig, pkg)) {
                        Slog.i(TAG, "Adopting permissions from " + origName + " to "
                                + pkg.getPackageName());
                        mSettings.mPermissions.transferPermissions(origName, pkg.getPackageName());
                        mPermissionManager.transferPermissions(origName, pkg.getPackageName());
                    }
                }
            }
@@ -17928,7 +17929,7 @@ public class PackageManagerService extends IPackageManager.Stub
            final int N = ArrayUtils.size(parsedPackage.getPermissions());
            for (int i = N - 1; i >= 0; i--) {
                final ParsedPermission perm = parsedPackage.getPermissions().get(i);
                final BasePermission bp = mPermissionManager.getPermissionTEMP(perm.getName());
                final Permission bp = mPermissionManager.getPermissionTEMP(perm.getName());
                // Don't allow anyone but the system to define ephemeral permissions.
                if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
@@ -24216,9 +24217,9 @@ public class PackageManagerService extends IPackageManager.Stub
    boolean readPermissionStateForUser(@UserIdInt int userId) {
        synchronized (mPackages) {
            mPermissionManager.writeStateToPackageSettingsTEMP();
            mPermissionManager.writeLegacyPermissionStateTEMP();
            mSettings.readPermissionStateForUserSyncLPr(userId);
            mPermissionManager.readStateFromPackageSettingsTEMP();
            mPermissionManager.readLegacyPermissionStateTEMP();
            return mPmInternal.isPermissionUpgradeNeeded(userId);
        }
    }
@@ -26361,13 +26362,14 @@ public class PackageManagerService extends IPackageManager.Stub
    }
    /**
     * Temporary method that wraps mSettings.writeLPr() and calls
     * mPermissionManager.writeStateToPackageSettingsTEMP() beforehand.
     * Temporary method that wraps mSettings.writeLPr() and calls mPermissionManager's
     * writeLegacyPermissionsTEMP() and writeLegacyPermissionStateTEMP() beforehand.
     *
     * TODO(zhanghai): This should be removed once we finish migration of permission storage.
     */
    private void writeSettingsLPrTEMP() {
        mPermissionManager.writeStateToPackageSettingsTEMP();
        mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions);
        mPermissionManager.writeLegacyPermissionStateTEMP();
        mSettings.writeLPr();
    }
+14 −53
Original line number Diff line number Diff line
@@ -107,11 +107,10 @@ import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.permission.LegacyPermissionSettings;
import com.android.server.pm.permission.LegacyPermissionState;
import com.android.server.pm.permission.LegacyPermissionState.PermissionState;
import com.android.server.pm.permission.PermissionSettings;
import com.android.server.utils.TimingsTraceAndSlog;

import libcore.io.IoUtils;
@@ -420,7 +419,7 @@ public final class Settings {
    public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);

    /** Settings and other information about permissions */
    final PermissionSettings mPermissions;
    final LegacyPermissionSettings mPermissions;

    private final LegacyPermissionDataProvider mPermissionDataProvider;

@@ -440,11 +439,10 @@ public final class Settings {
        mKernelMappingFilename = null;
    }

    Settings(File dataDir, PermissionSettings permissionSettings,
            RuntimePermissionsPersistence runtimePermissionsPersistence,
    Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
            LegacyPermissionDataProvider permissionDataProvider, Object lock) {
        mLock = lock;
        mPermissions = permissionSettings;
        mPermissions = new LegacyPermissionSettings(lock);
        mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
                runtimePermissionsPersistence);
        mPermissionDataProvider = permissionDataProvider;
@@ -489,10 +487,6 @@ public final class Settings {
        mRenamedPackages.remove(pkgName);
    }

    public boolean canPropagatePermissionToInstantApp(String permName) {
        return mPermissions.canPropagatePermissionToInstantApp(permName);
    }

    /** Gets and optionally creates a new shared user id. */
    SharedUserSetting getSharedUserLPw(String name, int pkgFlags, int pkgPrivateFlags,
            boolean create) throws PackageManagerException {
@@ -2128,23 +2122,14 @@ public final class Settings {
            String tagName = parser.getName();
            if (tagName.equals(TAG_ITEM)) {
                String name = parser.getAttributeValue(null, ATTR_NAME);

                BasePermission bp = mPermissions.getPermission(name);
                if (bp == null) {
                    Slog.w(PackageManagerService.TAG, "Unknown permission: " + name);
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                }

                String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED);
                final boolean granted = grantedStr == null
                        || Boolean.parseBoolean(grantedStr);

                String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS);
                final int flags = (flagsStr != null)
                        ? Integer.parseInt(flagsStr, 16) : 0;

                permissionsState.putInstallPermissionState(new PermissionState(bp, granted, flags));
                permissionsState.putInstallPermissionState(new PermissionState(name, granted,
                        flags));
            } else {
                Slog.w(PackageManagerService.TAG, "Unknown element under <permissions>: "
                        + parser.getName());
@@ -2867,10 +2852,6 @@ public final class Settings {
        }
    }

    void writePermissionLPr(XmlSerializer serializer, BasePermission bp) throws IOException {
        bp.writeLPr(serializer);
    }

    boolean readLPw(@NonNull List<UserInfo> users) {
        FileInputStream str = null;
        if (mBackupSettingsFilename.exists()) {
@@ -4813,13 +4794,7 @@ public final class Settings {
                        && !permissionNames.contains(perm)) {
                    continue;
                }
                pw.print(prefix); pw.print("    "); pw.print(perm);
                final BasePermission bp = mPermissions.getPermission(perm);
                if (bp != null && bp.isHardOrSoftRestricted()) {
                    pw.println(": restricted=true");
                } else {
                    pw.println();
                }
                pw.print(prefix); pw.print("    "); pw.println(perm);
            }
        }

@@ -5024,7 +4999,9 @@ public final class Settings {

    void dumpPermissionsLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
            DumpState dumpState) {
        mPermissions.dumpPermissions(pw, packageName, permissionNames,
        LegacyPermissionSettings.dumpPermissions(pw, packageName, permissionNames,
                mPermissionDataProvider.getLegacyPermissions(),
                mPermissionDataProvider.getAllAppOpPermissionPackages(),
                (mReadExternalStorageEnforced == Boolean.TRUE), dumpState);
    }

@@ -5544,18 +5521,11 @@ public final class Settings {
            int permissionsSize = permissions.size();
            for (int i = 0; i < permissionsSize; i++) {
                RuntimePermissionsState.PermissionState permission = permissions.get(i);

                String name = permission.getName();
                BasePermission basePermission = mPermissions.getPermission(name);
                if (basePermission == null) {
                    Slog.w(PackageManagerService.TAG, "Unknown permission:" + name);
                    continue;
                }
                boolean granted = permission.isGranted();
                int flags = permission.getFlags();

                permissionsState.putRuntimePermissionState(new PermissionState(basePermission,
                        granted, flags), userId);
                permissionsState.putRuntimePermissionState(new PermissionState(name, granted,
                        flags), userId);
            }
        }

@@ -5650,23 +5620,14 @@ public final class Settings {
                switch (parser.getName()) {
                    case TAG_ITEM: {
                        String name = parser.getAttributeValue(null, ATTR_NAME);
                        BasePermission bp = mPermissions.getPermission(name);
                        if (bp == null) {
                            Slog.w(PackageManagerService.TAG, "Unknown permission:" + name);
                            XmlUtils.skipCurrentTag(parser);
                            continue;
                        }

                        String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED);
                        final boolean granted = grantedStr == null
                                || Boolean.parseBoolean(grantedStr);

                        String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS);
                        final int flags = (flagsStr != null)
                                ? Integer.parseInt(flagsStr, 16) : 0;

                        permissionsState.putRuntimePermissionState(new PermissionState(bp, granted,
                                flags), userId);
                        permissionsState.putRuntimePermissionState(new PermissionState(name,
                                granted, flags), userId);
                    }
                    break;
                }
+253 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2006 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.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PermissionInfo;
import android.util.Log;

import com.android.server.pm.DumpState;
import com.android.server.pm.PackageManagerService;

import libcore.util.EmptyArray;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * Legacy permission definition.
 */
//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public final class LegacyPermission {
    /**
     * The permission is defined in a manifest.
     */
    public static final int TYPE_MANIFEST = 0;

    /**
     * The permission is defined in a system config.
     */
    public static final int TYPE_CONFIG = 1;

    /**
     * The permission is defined dynamically.
     */
    public static final int TYPE_DYNAMIC = 2;

    /**
     * @hide
     */
    @IntDef({
            TYPE_MANIFEST,
            TYPE_CONFIG,
            TYPE_DYNAMIC,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface PermissionType {}

    private static final String ATTR_NAME = "name";
    private static final String ATTR_PACKAGE = "package";
    private static final String TAG_ITEM = "item";

    @NonNull
    private final PermissionInfo mPermissionInfo;
    @PermissionType
    private final int mType;
    private final int mUid;
    @NonNull
    private final int[] mGids;

    /**
     * Create a new instance of this class.
     *
     * @param permissionInfo the {@link PermissionInfo} for the permission
     * @param type the type of the permission
     * @param uid the UID defining the permission
     * @param gids the GIDs associated with the permission
     */
    public LegacyPermission(@NonNull PermissionInfo permissionInfo, @PermissionType int type,
            int uid, @NonNull int[] gids) {
        mPermissionInfo = permissionInfo;
        mType = type;
        mUid = uid;
        mGids = gids;
    }

    private LegacyPermission(@NonNull String name, @NonNull String packageName,
            @PermissionType int type) {
        mPermissionInfo = new PermissionInfo();
        mPermissionInfo.name = name;
        mPermissionInfo.packageName = packageName;
        // Default to most conservative protection level.
        mPermissionInfo.protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
        mType = type;
        mUid = 0;
        mGids = EmptyArray.INT;
    }

    /**
     * Get the {@link PermissionInfo} for this mission.
     *
     * @return the {@link PermissionInfo}
     */
    @NonNull
    public PermissionInfo getPermissionInfo() {
        return mPermissionInfo;
    }

    /**
     * Get the type of this mission.
     *
     * @return the type
     */
    public int getType() {
        return mType;
    }

    /**
     * @hide
     */
    public static boolean read(@NonNull Map<String, LegacyPermission> out,
            @NonNull XmlPullParser parser) {
        final String tagName = parser.getName();
        if (!tagName.equals(TAG_ITEM)) {
            return false;
        }
        final String name = parser.getAttributeValue(null, ATTR_NAME);
        final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
        final String ptype = parser.getAttributeValue(null, "type");
        if (name == null || packageName == null) {
            PackageManagerService.reportSettingsProblem(Log.WARN,
                    "Error in package manager settings: permissions has" + " no name at "
                            + parser.getPositionDescription());
            return false;
        }
        final boolean dynamic = "dynamic".equals(ptype);
        LegacyPermission bp = out.get(name);
        // If the permission is builtin, do not clobber it.
        if (bp == null || bp.mType != TYPE_CONFIG) {
            bp = new LegacyPermission(name.intern(), packageName,
                    dynamic ? TYPE_DYNAMIC : TYPE_MANIFEST);
        }
        bp.mPermissionInfo.protectionLevel = readInt(parser, null, "protection",
                PermissionInfo.PROTECTION_NORMAL);
        bp.mPermissionInfo.protectionLevel = PermissionInfo.fixProtectionLevel(
                bp.mPermissionInfo.protectionLevel);
        if (dynamic) {
            bp.mPermissionInfo.icon = readInt(parser, null, "icon", 0);
            bp.mPermissionInfo.nonLocalizedLabel = parser.getAttributeValue(null, "label");
        }
        out.put(bp.mPermissionInfo.name, bp);
        return true;
    }

    private static int readInt(@NonNull XmlPullParser parser, @Nullable String namespace,
            @NonNull String name, int defaultValue) {
        final String value = parser.getAttributeValue(namespace, name);
        if (value == null) {
            return defaultValue;
        }
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException e) {
            PackageManagerService.reportSettingsProblem(Log.WARN,
                    "Error in package manager settings: attribute " + name
                            + " has bad integer value " + value + " at "
                            + parser.getPositionDescription());
            return defaultValue;
        }
    }

    /**
     * @hide
     */
    public void write(@NonNull XmlSerializer serializer) throws IOException {
        if (mPermissionInfo.packageName == null) {
            return;
        }
        serializer.startTag(null, TAG_ITEM);
        serializer.attribute(null, ATTR_NAME, mPermissionInfo.name);
        serializer.attribute(null, ATTR_PACKAGE, mPermissionInfo.packageName);
        if (mPermissionInfo.protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
            serializer.attribute(null, "protection",
                    Integer.toString(mPermissionInfo.protectionLevel));
        }
        if (mType == TYPE_DYNAMIC) {
            serializer.attribute(null, "type", "dynamic");
            if (mPermissionInfo.icon != 0) {
                serializer.attribute(null, "icon", Integer.toString(mPermissionInfo.icon));
            }
            if (mPermissionInfo.nonLocalizedLabel != null) {
                serializer.attribute(null, "label", mPermissionInfo.nonLocalizedLabel.toString());
            }
        }
        serializer.endTag(null, TAG_ITEM);
    }

    /**
     * @hide
     */
    public boolean dump(@NonNull PrintWriter pw, @NonNull String packageName,
            @NonNull Set<String> permissionNames, boolean readEnforced, boolean printedSomething,
            @NonNull DumpState dumpState) {
        if (packageName != null && !packageName.equals(mPermissionInfo.packageName)) {
            return false;
        }
        if (permissionNames != null && !permissionNames.contains(mPermissionInfo.name)) {
            return false;
        }
        if (!printedSomething) {
            if (dumpState.onTitlePrinted()) {
                pw.println();
            }
            pw.println("Permissions:");
        }
        pw.print("  Permission ["); pw.print(mPermissionInfo.name); pw.print("] (");
        pw.print(Integer.toHexString(System.identityHashCode(this)));
        pw.println("):");
        pw.print("    sourcePackage="); pw.println(mPermissionInfo.packageName);
        pw.print("    uid="); pw.print(mUid);
        pw.print(" gids="); pw.print(Arrays.toString(mGids));
        pw.print(" type="); pw.print(mType);
        pw.print(" prot=");
        pw.println(PermissionInfo.protectionToString(mPermissionInfo.protectionLevel));
        if (mPermissionInfo != null) {
            pw.print("    perm="); pw.println(mPermissionInfo);
            if ((mPermissionInfo.flags & PermissionInfo.FLAG_INSTALLED) == 0
                    || (mPermissionInfo.flags & PermissionInfo.FLAG_REMOVED) != 0) {
                pw.print("    flags=0x"); pw.println(Integer.toHexString(mPermissionInfo.flags));
            }
        }
        if (Objects.equals(mPermissionInfo.name,
                android.Manifest.permission.READ_EXTERNAL_STORAGE)) {
            pw.print("    enforced=");
            pw.println(readEnforced);
        }
        return true;
    }
}
+20 −0
Original line number Diff line number Diff line
@@ -19,11 +19,31 @@ package com.android.server.pm.permission;
import android.annotation.AppIdInt;
import android.annotation.NonNull;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * An interface for legacy code to read permission data in order to maintain compatibility.
 */
//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public interface LegacyPermissionDataProvider {
    /**
     * Get all the legacy permissions currently registered in the system.
     *
     * @return the legacy permissions
     */
    @NonNull
    List<LegacyPermission> getLegacyPermissions();

    /**
     * Get all the package names requesting app op permissions.
     *
     * @return a map of app op permission names to package names requesting them
     */
    @NonNull
    Map<String, Set<String>> getAllAppOpPermissionPackages();

    /**
     * Get the legacy permission state of an app ID, either a package or a shared user.
     *
Loading