diff options
| author | 2020-10-29 22:41:19 +0000 | |
|---|---|---|
| committer | 2020-10-29 22:41:19 +0000 | |
| commit | 4930b4bbede2b5b6ed0a33ff95083f7560eec40e (patch) | |
| tree | d6b41bf9fce728beef4b2d143a6780162ed979cf | |
| parent | 7e3010b2861c428f24bbfa8b55dea850534bcb23 (diff) | |
| parent | 4583da1a691e69371e1fbfef5a9413fc5abc7d8c (diff) | |
Merge "Split PermissionSettings into LegacyPermissionSettings and PermissionRegistry."
15 files changed, 1192 insertions, 804 deletions
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java index c0329b2b2fe6..efbdfeaaeb93 100644 --- a/services/core/java/com/android/server/pm/InstantAppRegistry.java +++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java @@ -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, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e63a05aa6b73..4fdb9fbb3b3f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -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()); } } } @@ -17943,7 +17944,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 @@ -24231,9 +24232,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); } } @@ -26376,13 +26377,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(); } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index c7304c2695c9..cd9a4e72672f 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -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; } diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermission.java b/services/core/java/com/android/server/pm/permission/LegacyPermission.java new file mode 100644 index 000000000000..a19a05ae021c --- /dev/null +++ b/services/core/java/com/android/server/pm/permission/LegacyPermission.java @@ -0,0 +1,253 @@ +/* + * 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; + } +} diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java index 346a2c527fcb..0e790b1899ed 100644 --- a/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java +++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java @@ -19,12 +19,32 @@ 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. * * @param appId the app ID diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionSettings.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionSettings.java new file mode 100644 index 000000000000..cc0b79872ba0 --- /dev/null +++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionSettings.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2017 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.NonNull; +import android.annotation.Nullable; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.XmlUtils; +import com.android.server.pm.DumpState; +import com.android.server.pm.PackageManagerService; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Legacy permission settings for migration. + */ +public class LegacyPermissionSettings { + /** + * All of the permissions known to the system. The mapping is from permission + * name to permission object. + */ + @GuardedBy("mLock") + private final ArrayMap<String, LegacyPermission> mPermissions = new ArrayMap<>(); + + /** + * All permission trees known to the system. The mapping is from permission tree + * name to permission object. + */ + @GuardedBy("mLock") + private final ArrayMap<String, LegacyPermission> mPermissionTrees = new ArrayMap<>(); + + @NonNull + private final Object mLock; + + public LegacyPermissionSettings(@NonNull Object lock) { + mLock = lock; + } + + @NonNull + public List<LegacyPermission> getPermissions() { + synchronized (mLock) { + return new ArrayList<>(mPermissions.values()); + } + } + + @NonNull + public List<LegacyPermission> getPermissionTrees() { + synchronized (mLock) { + return new ArrayList<>(mPermissionTrees.values()); + } + } + + public void replacePermissions(@NonNull List<LegacyPermission> permissions) { + synchronized (mLock) { + mPermissions.clear(); + final int permissionsSize = permissions.size(); + for (int i = 0; i < permissionsSize; i++) { + final LegacyPermission permission = permissions.get(i); + mPermissions.put(permission.getPermissionInfo().name, permission); + } + } + } + + public void replacePermissionTrees(@NonNull List<LegacyPermission> permissionTrees) { + synchronized (mLock) { + mPermissionTrees.clear(); + final int permissionsSize = permissionTrees.size(); + for (int i = 0; i < permissionsSize; i++) { + final LegacyPermission permissionTree = permissionTrees.get(i); + mPermissionTrees.put(permissionTree.getPermissionInfo().name, permissionTree); + } + } + } + + public void readPermissions(@NonNull XmlPullParser parser) throws IOException, + XmlPullParserException { + synchronized (mLock) { + readPermissions(mPermissions, parser); + } + } + + public void readPermissionTrees(@NonNull XmlPullParser parser) throws IOException, + XmlPullParserException { + synchronized (mLock) { + readPermissions(mPermissionTrees, parser); + } + } + + public static void readPermissions(@NonNull ArrayMap<String, LegacyPermission> out, + @NonNull XmlPullParser parser) throws IOException, XmlPullParserException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + if (!LegacyPermission.read(out, parser)) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unknown element reading permissions: " + parser.getName() + " at " + + parser.getPositionDescription()); + } + XmlUtils.skipCurrentTag(parser); + } + } + + public void writePermissions(@NonNull XmlSerializer serializer) throws IOException { + synchronized (mLock) { + for (LegacyPermission bp : mPermissions.values()) { + bp.write(serializer); + } + } + } + + public void writePermissionTrees(@NonNull XmlSerializer serializer) throws IOException { + synchronized (mLock) { + for (LegacyPermission bp : mPermissionTrees.values()) { + bp.write(serializer); + } + } + } + + public static void dumpPermissions(@NonNull PrintWriter pw, @Nullable String packageName, + @Nullable ArraySet<String> permissionNames, @NonNull List<LegacyPermission> permissions, + @NonNull Map<String, Set<String>> appOpPermissionPackages, + boolean externalStorageEnforced, @NonNull DumpState dumpState) { + boolean printedSomething = false; + final int permissionsSize = permissions.size(); + for (int i = 0; i < permissionsSize; i++) { + final LegacyPermission permission = permissions.get(i); + printedSomething = permission.dump(pw, packageName, permissionNames, + externalStorageEnforced, printedSomething, dumpState); + } + if (packageName == null && permissionNames == null) { + boolean firstEntry = true; + for (final Map.Entry<String, Set<String>> entry : appOpPermissionPackages.entrySet()) { + if (firstEntry) { + firstEntry = false; + if (dumpState.onTitlePrinted()) { + pw.println(); + } + pw.println("AppOp Permissions:"); + } + pw.print(" AppOp Permission "); + pw.print(entry.getKey()); + pw.println(":"); + for (final String appOpPackageName : entry.getValue()) { + pw.print(" "); + pw.println(appOpPackageName); + } + } + } + } +} diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java index 63f69cede59c..0e60367c243b 100644 --- a/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java +++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java @@ -252,7 +252,7 @@ public final class LegacyPermissionState { */ public static final class PermissionState { @NonNull - private final BasePermission mPermission; + private final String mName; private final boolean mGranted; @@ -261,40 +261,30 @@ public final class LegacyPermissionState { /** * Create a new instance of this class. * - * @param permission the {@link BasePermission} for the permission + * @param name the name of the permission * @param granted whether the permission is granted * @param flags the permission flags */ - public PermissionState(@NonNull BasePermission permission, boolean granted, int flags) { - mPermission = permission; + public PermissionState(@NonNull String name, boolean granted, int flags) { + mName = name; mGranted = granted; mFlags = flags; } private PermissionState(@NonNull PermissionState other) { - mPermission = other.mPermission; + mName = other.mName; mGranted = other.mGranted; mFlags = other.mFlags; } /** - * Get the {@link BasePermission} for the permission. - * - * @return the {@link BasePermission} - */ - @NonNull - public BasePermission getPermission() { - return mPermission; - } - - /** * Get the permission name. * * @return the permission name */ @NonNull public String getName() { - return mPermission.getName(); + return mName; } /** diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/Permission.java index 155d71673e06..c121e6b4a763 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/Permission.java @@ -19,6 +19,7 @@ package com.android.server.pm.permission; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PermissionInfo; @@ -28,31 +29,25 @@ import android.os.UserHandle; import android.util.Log; import android.util.Slog; -import com.android.server.pm.DumpState; import com.android.server.pm.PackageManagerService; import com.android.server.pm.parsing.pkg.AndroidPackage; 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.Collection; -import java.util.Map; import java.util.Objects; -import java.util.Set; -public final class BasePermission { - private static final String TAG = "PackageManager"; +/** + * Permission definition. + */ +public final class Permission { + private static final String TAG = "Permission"; - public static final int TYPE_MANIFEST = 0; - public static final int TYPE_CONFIG = 1; - public static final int TYPE_DYNAMIC = 2; + public static final int TYPE_MANIFEST = LegacyPermission.TYPE_MANIFEST; + public static final int TYPE_CONFIG = LegacyPermission.TYPE_CONFIG; + public static final int TYPE_DYNAMIC = LegacyPermission.TYPE_DYNAMIC; @IntDef({ TYPE_MANIFEST, TYPE_CONFIG, @@ -70,18 +65,13 @@ public final class BasePermission { @Retention(RetentionPolicy.SOURCE) public @interface ProtectionLevel {} - private static final String ATTR_NAME = "name"; - private static final String ATTR_PACKAGE = "package"; - private static final String TAG_ITEM = "item"; - - private boolean mPermissionDefinitionChanged; - @NonNull private PermissionInfo mPermissionInfo; private boolean mReconciled; - private final @PermissionType int mType; + @PermissionType + private final int mType; /** UID that owns the definition of this permission */ private int mUid; @@ -96,7 +86,10 @@ public final class BasePermission { */ private boolean mGidsPerUser; - public BasePermission(@NonNull String name, String packageName, @PermissionType int type) { + private boolean mDefinitionChanged; + + public Permission(@NonNull String name, @NonNull String packageName, + @PermissionType int type) { mPermissionInfo = new PermissionInfo(); mPermissionInfo.name = name; mPermissionInfo.packageName = packageName; @@ -105,10 +98,27 @@ public final class BasePermission { mType = type; } - @Override - public String toString() { - return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " - + mPermissionInfo.name + "}"; + public Permission(@NonNull PermissionInfo permissionInfo, @PermissionType int type) { + mPermissionInfo = permissionInfo; + mType = type; + } + + @NonNull + public PermissionInfo getPermissionInfo() { + return mPermissionInfo; + } + + public void setPermissionInfo(@Nullable PermissionInfo permissionInfo) { + if (permissionInfo != null) { + mPermissionInfo = permissionInfo; + } else { + final PermissionInfo newPermissionInfo = new PermissionInfo(); + newPermissionInfo.name = mPermissionInfo.name; + newPermissionInfo.packageName = mPermissionInfo.packageName; + newPermissionInfo.protectionLevel = mPermissionInfo.protectionLevel; + mPermissionInfo = newPermissionInfo; + } + mReconciled = permissionInfo != null; } @NonNull @@ -120,14 +130,11 @@ public final class BasePermission { return mPermissionInfo.protectionLevel; } + @NonNull public String getPackageName() { return mPermissionInfo.packageName; } - public boolean isPermissionDefinitionChanged() { - return mPermissionDefinitionChanged; - } - public int getType() { return mType; } @@ -136,34 +143,26 @@ public final class BasePermission { return mUid; } - public void setGids(@NonNull int[] gids, boolean gidsPerUser) { - mGids = gids; - mGidsPerUser = gidsPerUser; + public boolean hasGids() { + return mGids.length != 0; } - public void setPermissionInfo(@Nullable PermissionInfo permissionInfo) { - if (permissionInfo != null) { - mPermissionInfo = permissionInfo; - } else { - final PermissionInfo newPermissionInfo = new PermissionInfo(); - newPermissionInfo.name = mPermissionInfo.name; - newPermissionInfo.packageName = mPermissionInfo.packageName; - newPermissionInfo.protectionLevel = mPermissionInfo.protectionLevel; - mPermissionInfo = newPermissionInfo; - } - mReconciled = permissionInfo != null; + @NonNull + public int[] getRawGids() { + return mGids; } - public void setPermissionDefinitionChanged(boolean shouldOverride) { - mPermissionDefinitionChanged = shouldOverride; + public boolean areGidsPerUser() { + return mGidsPerUser; } - public boolean hasGids() { - return mGids.length != 0; + public void setGids(@NonNull int[] gids, boolean gidsPerUser) { + mGids = gids; + mGidsPerUser = gidsPerUser; } @NonNull - public int[] computeGids(int userId) { + public int[] computeGids(@UserIdInt int userId) { if (mGidsPerUser) { final int[] userGids = new int[mGids.length]; for (int i = 0; i < mGids.length; i++) { @@ -176,19 +175,28 @@ public final class BasePermission { } } - public int calculateFootprint(BasePermission perm) { - if (mUid == perm.mUid) { - return perm.mPermissionInfo.name.length() + perm.mPermissionInfo.calculateFootprint(); + public boolean isDefinitionChanged() { + return mDefinitionChanged; + } + + public void setDefinitionChanged(boolean definitionChanged) { + mDefinitionChanged = definitionChanged; + } + + public int calculateFootprint(@NonNull Permission permission) { + if (mUid == permission.mUid) { + return permission.mPermissionInfo.name.length() + + permission.mPermissionInfo.calculateFootprint(); } return 0; } - public boolean isPermission(ParsedPermission perm) { + public boolean isPermission(@NonNull ParsedPermission parsedPermission) { if (mPermissionInfo == null) { return false; } - return Objects.equals(mPermissionInfo.packageName, perm.getPackageName()) - && Objects.equals(mPermissionInfo.name, perm.getName()); + return Objects.equals(mPermissionInfo.packageName, parsedPermission.getPackageName()) + && Objects.equals(mPermissionInfo.name, parsedPermission.getName()); } public boolean isDynamic() { @@ -323,8 +331,8 @@ public final class BasePermission { return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO) != 0; } - public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) { - if (!origPackageName.equals(mPermissionInfo.packageName)) { + public void transfer(@NonNull String oldPackageName, @NonNull String newPackageName) { + if (!oldPackageName.equals(mPermissionInfo.packageName)) { return; } final PermissionInfo newPermissionInfo = new PermissionInfo(); @@ -339,28 +347,29 @@ public final class BasePermission { } public boolean addToTree(@ProtectionLevel int protectionLevel, - @NonNull PermissionInfo permissionInfo, @NonNull BasePermission tree) { + @NonNull PermissionInfo permissionInfo, @NonNull Permission permissionTree) { final boolean changed = (mPermissionInfo.protectionLevel != protectionLevel || !mReconciled - || mUid != tree.mUid + || mUid != permissionTree.mUid || !Objects.equals(mPermissionInfo.packageName, - tree.mPermissionInfo.packageName) + permissionTree.mPermissionInfo.packageName) || !comparePermissionInfos(mPermissionInfo, permissionInfo)); mPermissionInfo = new PermissionInfo(permissionInfo); - mPermissionInfo.packageName = tree.mPermissionInfo.packageName; + mPermissionInfo.packageName = permissionTree.mPermissionInfo.packageName; mPermissionInfo.protectionLevel = protectionLevel; mReconciled = true; - mUid = tree.mUid; + mUid = permissionTree.mUid; return changed; } - public void updateDynamicPermission(Collection<BasePermission> permissionTrees) { - if (PackageManagerService.DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name=" - + getName() + " pkg=" + getPackageName() - + " info=" + mPermissionInfo); + public void updateDynamicPermission(@NonNull Collection<Permission> permissionTrees) { + if (PackageManagerService.DEBUG_SETTINGS) { + Log.v(TAG, "Dynamic permission: name=" + getName() + " pkg=" + getPackageName() + + " info=" + mPermissionInfo); + } if (mType == TYPE_DYNAMIC) { - final BasePermission tree = findPermissionTree(permissionTrees, mPermissionInfo.name); + final Permission tree = findPermissionTree(permissionTrees, mPermissionInfo.name); if (tree != null) { mPermissionInfo.packageName = tree.mPermissionInfo.packageName; mReconciled = true; @@ -369,19 +378,21 @@ public final class BasePermission { } } - static BasePermission createOrUpdate(PackageManagerInternal packageManagerInternal, - @Nullable BasePermission bp, @NonNull PermissionInfo p, - @NonNull AndroidPackage pkg, Collection<BasePermission> permissionTrees, + @NonNull + static Permission createOrUpdate(PackageManagerInternal packageManagerInternal, + @Nullable Permission permission, @NonNull PermissionInfo permissionInfo, + @NonNull AndroidPackage pkg, @NonNull Collection<Permission> permissionTrees, boolean chatty) { // Allow system apps to redefine non-system permissions boolean ownerChanged = false; - if (bp != null && !Objects.equals(bp.mPermissionInfo.packageName, p.packageName)) { + if (permission != null && !Objects.equals(permission.mPermissionInfo.packageName, + permissionInfo.packageName)) { final boolean currentOwnerIsSystem; - if (!bp.mReconciled) { + if (!permission.mReconciled) { currentOwnerIsSystem = false; } else { AndroidPackage currentPackage = packageManagerInternal.getPackage( - bp.mPermissionInfo.packageName); + permission.mPermissionInfo.packageName); if (currentPackage == null) { currentOwnerIsSystem = false; } else { @@ -390,54 +401,56 @@ public final class BasePermission { } if (pkg.isSystem()) { - if (bp.mType == BasePermission.TYPE_CONFIG && !bp.mReconciled) { + if (permission.mType == Permission.TYPE_CONFIG && !permission.mReconciled) { // It's a built-in permission and no owner, take ownership now - p.flags |= PermissionInfo.FLAG_INSTALLED; - bp.mPermissionInfo = p; - bp.mReconciled = true; - bp.mUid = pkg.getUid(); + permissionInfo.flags |= PermissionInfo.FLAG_INSTALLED; + permission.mPermissionInfo = permissionInfo; + permission.mReconciled = true; + permission.mUid = pkg.getUid(); } else if (!currentOwnerIsSystem) { String msg = "New decl " + pkg + " of permission " - + p.name + " is system; overriding " + bp.mPermissionInfo.packageName; + + permissionInfo.name + " is system; overriding " + + permission.mPermissionInfo.packageName; PackageManagerService.reportSettingsProblem(Log.WARN, msg); ownerChanged = true; - bp = null; + permission = null; } } } - if (bp == null) { - bp = new BasePermission(p.name, p.packageName, TYPE_MANIFEST); + if (permission == null) { + permission = new Permission(permissionInfo.name, permissionInfo.packageName, + TYPE_MANIFEST); } - boolean wasNormal = bp.isNormal(); + boolean wasNormal = permission.isNormal(); StringBuilder r = null; - if (!bp.mReconciled) { - if (bp.mPermissionInfo.packageName == null - || bp.mPermissionInfo.packageName.equals(p.packageName)) { - final BasePermission tree = findPermissionTree(permissionTrees, p.name); + if (!permission.mReconciled) { + if (permission.mPermissionInfo.packageName == null + || permission.mPermissionInfo.packageName.equals(permissionInfo.packageName)) { + final Permission tree = findPermissionTree(permissionTrees, permissionInfo.name); if (tree == null - || tree.mPermissionInfo.packageName.equals(p.packageName)) { - p.flags |= PermissionInfo.FLAG_INSTALLED; - bp.mPermissionInfo = p; - bp.mReconciled = true; - bp.mUid = pkg.getUid(); + || tree.mPermissionInfo.packageName.equals(permissionInfo.packageName)) { + permissionInfo.flags |= PermissionInfo.FLAG_INSTALLED; + permission.mPermissionInfo = permissionInfo; + permission.mReconciled = true; + permission.mUid = pkg.getUid(); if (chatty) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } - r.append(p.name); + r.append(permissionInfo.name); } } else { - Slog.w(TAG, "Permission " + p.name + " from package " - + p.packageName + " ignored: base tree " + Slog.w(TAG, "Permission " + permissionInfo.name + " from package " + + permissionInfo.packageName + " ignored: base tree " + tree.mPermissionInfo.name + " is from package " + tree.mPermissionInfo.packageName); } } else { - Slog.w(TAG, "Permission " + p.name + " from package " - + p.packageName + " ignored: original from " - + bp.mPermissionInfo.packageName); + Slog.w(TAG, "Permission " + permissionInfo.name + " from package " + + permissionInfo.packageName + " ignored: original from " + + permission.mPermissionInfo.packageName); } } else if (chatty) { if (r == null) { @@ -446,42 +459,47 @@ public final class BasePermission { r.append(' '); } r.append("DUP:"); - r.append(p.name); + r.append(permissionInfo.name); } - if (bp.isRuntime() && (ownerChanged || wasNormal)) { + if (permission.isRuntime() && (ownerChanged || wasNormal)) { // If this is a runtime permission and the owner has changed, or this was a normal // permission, then permission state should be cleaned up - bp.mPermissionDefinitionChanged = true; + permission.mDefinitionChanged = true; } if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) { Log.d(TAG, " Permissions: " + r); } - return bp; + return permission; } - static BasePermission enforcePermissionTree( - Collection<BasePermission> permissionTrees, String permName, int callingUid) { - if (permName != null) { - BasePermission bp = findPermissionTree(permissionTrees, permName); - if (bp != null) { - if (bp.mUid == UserHandle.getAppId(callingUid)) { - return bp; + @NonNull + public static Permission enforcePermissionTree(@NonNull Collection<Permission> permissionTrees, + @NonNull String permissionName, int callingUid) { + if (permissionName != null) { + final Permission permissionTree = Permission.findPermissionTree(permissionTrees, + permissionName); + if (permissionTree != null) { + if (permissionTree.getUid() == UserHandle.getAppId(callingUid)) { + return permissionTree; } throw new SecurityException("Calling uid " + callingUid + " is not allowed to add to permission tree " - + bp.mPermissionInfo.name + " owned by uid " + bp.mUid); + + permissionTree.getName() + " owned by uid " + + permissionTree.getUid()); } } - throw new SecurityException("No permission tree found for " + permName); + throw new SecurityException("No permission tree found for " + permissionName); } - private static BasePermission findPermissionTree( - Collection<BasePermission> permissionTrees, String permName) { - for (BasePermission bp : permissionTrees) { - if (permName.startsWith(bp.mPermissionInfo.name) - && permName.length() > bp.mPermissionInfo.name.length() - && permName.charAt(bp.mPermissionInfo.name.length()) == '.') { - return bp; + @Nullable + private static Permission findPermissionTree(@NonNull Collection<Permission> permissionTrees, + @NonNull String permissionName) { + for (final Permission permissionTree : permissionTrees) { + final String permissionTreeName = permissionTree.getName(); + if (permissionName.startsWith(permissionTreeName) + && permissionName.length() > permissionTreeName.length() + && permissionName.charAt(permissionTreeName.length()) == '.') { + return permissionTree; } } return null; @@ -512,7 +530,7 @@ public final class BasePermission { @NonNull public PermissionInfo generatePermissionInfo(int flags, int targetSdkVersion) { - PermissionInfo permissionInfo; + final PermissionInfo permissionInfo; if (mPermissionInfo != null) { permissionInfo = new PermissionInfo(mPermissionInfo); if ((flags & PackageManager.GET_META_DATA) != PackageManager.GET_META_DATA) { @@ -539,79 +557,6 @@ public final class BasePermission { return permissionInfo; } - public static boolean readLPw(@NonNull Map<String, BasePermission> 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); - BasePermission bp = out.get(name); - // If the permission is builtin, do not clobber it. - if (bp == null || bp.mType != TYPE_CONFIG) { - bp = new BasePermission(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(XmlPullParser parser, String ns, String name, int defValue) { - String v = parser.getAttributeValue(ns, name); - try { - if (v == null) { - return defValue; - } - return Integer.parseInt(v); - } catch (NumberFormatException e) { - PackageManagerService.reportSettingsProblem(Log.WARN, - "Error in package manager settings: attribute " + name - + " has bad integer value " + v + " at " - + parser.getPositionDescription()); - } - return defValue; - } - - public void writeLPr(@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); - } - private static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) { if (pi1.icon != pi2.icon) return false; if (pi1.logo != pi2.logo) return false; @@ -627,42 +572,4 @@ public final class BasePermission { //if (pi1.descriptionRes != pi2.descriptionRes) return false; return true; } - - public boolean dumpPermissionsLPr(@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(computeGids(UserHandle.USER_SYSTEM))); - 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; - } } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index da4ef63d6945..6d987aee8995 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -252,7 +252,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { /** Internal storage for permissions and related settings */ @GuardedBy("mLock") - private final PermissionSettings mSettings; + private final PermissionRegistry mRegistry; /** Injector that can be used to facilitate testing. */ private final Injector mInjector; @@ -387,7 +387,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { mLock = externalLock; mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class); mUserManagerInt = LocalServices.getService(UserManagerInternal.class); - mSettings = new PermissionSettings(mLock); + mRegistry = new PermissionRegistry(mLock); mAppOpsManager = context.getSystemService(AppOpsManager.class); mHandlerThread = new ServiceThread(TAG, @@ -409,10 +409,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { synchronized (mLock) { for (int i=0; i<permConfig.size(); i++) { final SystemConfig.PermissionEntry perm = permConfig.valueAt(i); - BasePermission bp = mSettings.getPermissionLocked(perm.name); + Permission bp = mRegistry.getPermissionLocked(perm.name); if (bp == null) { - bp = new BasePermission(perm.name, "android", BasePermission.TYPE_CONFIG); - mSettings.putPermissionLocked(perm.name, bp); + bp = new Permission(perm.name, "android", Permission.TYPE_CONFIG); + mRegistry.addPermissionLocked(bp); } if (perm.gids != null) { bp.setGids(perm.gids, perm.perUser); @@ -485,9 +485,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Nullable - BasePermission getPermission(String permName) { + Permission getPermission(String permName) { synchronized (mLock) { - return mSettings.getPermissionLocked(permName); + return mRegistry.getPermissionLocked(permName); } } @@ -501,7 +501,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return null; } synchronized (mLock) { - final ArraySet<String> pkgs = mSettings.mAppOpPermissionPackages.get(permName); + final ArraySet<String> pkgs = mRegistry.getAppOpPermissionPackagesLocked(permName); if (pkgs == null) { return null; } @@ -518,9 +518,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { return ParceledListSlice.emptyList(); } synchronized (mLock) { - final int n = mSettings.mPermissionGroups.size(); - final ArrayList<PermissionGroupInfo> out = new ArrayList<>(n); - for (ParsedPermissionGroup pg : mSettings.mPermissionGroups.values()) { + final List<PermissionGroupInfo> out = new ArrayList<>(); + for (ParsedPermissionGroup pg : mRegistry.getPermissionGroupsLocked()) { out.add(PackageInfoUtils.generatePermissionGroupInfo(pg, flags)); } return new ParceledListSlice<>(out); @@ -538,7 +537,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } synchronized (mLock) { return PackageInfoUtils.generatePermissionGroupInfo( - mSettings.mPermissionGroups.get(groupName), flags); + mRegistry.getPermissionGroupLocked(groupName), flags); } } @@ -555,7 +554,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int targetSdkVersion = getPermissionInfoCallingTargetSdkVersion(opPackage, callingUid); synchronized (mLock) { - final BasePermission bp = mSettings.getPermissionLocked(permName); + final Permission bp = mRegistry.getPermissionLocked(permName); if (bp == null) { return null; } @@ -585,11 +584,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { return null; } synchronized (mLock) { - if (groupName != null && !mSettings.mPermissionGroups.containsKey(groupName)) { + if (groupName != null && mRegistry.getPermissionGroupLocked(groupName) == null) { return null; } final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10); - for (BasePermission bp : mSettings.mPermissions.values()) { + for (Permission bp : mRegistry.getPermissionsLocked()) { if (Objects.equals(bp.getGroup(), groupName)) { out.add(bp.generatePermissionInfo(flags)); } @@ -607,24 +606,24 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (info.labelRes == 0 && info.nonLocalizedLabel == null) { throw new SecurityException("Label must be specified in permission"); } - final BasePermission tree = mSettings.enforcePermissionTree(info.name, callingUid); + final Permission tree = mRegistry.enforcePermissionTree(info.name, callingUid); final boolean added; final boolean changed; synchronized (mLock) { - BasePermission bp = mSettings.getPermissionLocked(info.name); + Permission bp = mRegistry.getPermissionLocked(info.name); added = bp == null; int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel); if (added) { enforcePermissionCapLocked(info, tree); - bp = new BasePermission(info.name, tree.getPackageName(), - BasePermission.TYPE_DYNAMIC); + bp = new Permission(info.name, tree.getPackageName(), + Permission.TYPE_DYNAMIC); } else if (!bp.isDynamic()) { throw new SecurityException("Not allowed to modify non-dynamic permission " + info.name); } changed = bp.addToTree(fixedLevel, info, tree); if (added) { - mSettings.putPermissionLocked(info.name, bp); + mRegistry.addPermissionLocked(bp); } } if (changed) { @@ -639,9 +638,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) { throw new SecurityException("Instant applications don't have access to this method"); } - final BasePermission tree = mSettings.enforcePermissionTree(permName, callingUid); + final Permission tree = mRegistry.enforcePermissionTree(permName, callingUid); synchronized (mLock) { - final BasePermission bp = mSettings.getPermissionLocked(permName); + final Permission bp = mRegistry.getPermissionLocked(permName); if (bp == null) { return; } @@ -650,7 +649,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { Slog.wtf(TAG, "Not allowed to modify non-dynamic permission " + permName); } - mSettings.removePermissionLocked(permName); + mRegistry.removePermissionLocked(permName); mPackageManagerInt.writeSettings(false); } } @@ -683,7 +682,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } synchronized (mLock) { - if (mSettings.getPermissionLocked(permName) == null) { + if (mRegistry.getPermissionLocked(permName) == null) { return 0; } @@ -808,10 +807,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - final BasePermission bp; + final Permission bp; final boolean permissionUpdated; synchronized (mLock) { - bp = mSettings.getPermissionLocked(permName); + bp = mRegistry.getPermissionLocked(permName); if (bp == null) { throw new IllegalArgumentException("Unknown permission: " + permName); } @@ -970,7 +969,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (isInstantApp) { - return mSettings.isPermissionInstant(permissionName); + return mRegistry.isPermissionInstant(permissionName); } return true; @@ -1232,7 +1231,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { private boolean checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission( @NonNull String permName) { synchronized (mLock) { - final BasePermission bp = mSettings.getPermissionLocked(permName); + final Permission bp = mRegistry.getPermissionLocked(permName); if (bp == null) { Slog.w(TAG, "No such permissions: " + permName); return false; @@ -1473,9 +1472,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown package: " + packageName); } - final BasePermission bp; + final Permission bp; synchronized (mLock) { - bp = mSettings.getPermissionLocked(permName); + bp = mRegistry.getPermissionLocked(permName); } if (bp == null) { throw new IllegalArgumentException("Unknown permission: " + permName); @@ -1627,7 +1626,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) { throw new IllegalArgumentException("Unknown package: " + packageName); } - final BasePermission bp = mSettings.getPermission(permName); + final Permission bp = mRegistry.getPermission(permName); if (bp == null) { throw new IllegalArgumentException("Unknown permission: " + permName); } @@ -1808,9 +1807,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int i = 0; i < permissionCount; i++) { final String permName = pkg.getRequestedPermissions().get(i); - final BasePermission bp; + final Permission bp; synchronized (mLock) { - bp = mSettings.getPermissionLocked(permName); + bp = mRegistry.getPermissionLocked(permName); } if (bp == null) { continue; @@ -2093,7 +2092,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return false; } - BasePermission permission = getPermission(permName); + Permission permission = getPermission(permName); if (permission == null) { return false; } @@ -2348,7 +2347,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int permNum = 0; permNum < numPermissions; permNum++) { String permName = permissionsToRevoke.get(permNum); - BasePermission bp = mSettings.getPermission(permName); + Permission bp = mRegistry.getPermission(permName); if (bp == null || !bp.isRuntime()) { continue; } @@ -2388,7 +2387,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } } - bp.setPermissionDefinitionChanged(false); + bp.setDefinitionChanged(false); } } @@ -2407,7 +2406,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // permissions for one app being granted to someone just because they happen // to be in a group defined by another app (before this had no implications). if (pkg.getTargetSdkVersion() > Build.VERSION_CODES.LOLLIPOP_MR1) { - p.setParsedPermissionGroup(mSettings.mPermissionGroups.get(p.getGroup())); + p.setParsedPermissionGroup(mRegistry.getPermissionGroupLocked(p.getGroup())); // Warn for a permission in an unknown group. if (DEBUG_PERMISSIONS && p.getGroup() != null && p.getParsedPermissionGroup() == null) { @@ -2418,24 +2417,24 @@ public class PermissionManagerService extends IPermissionManager.Stub { final PermissionInfo permissionInfo = PackageInfoUtils.generatePermissionInfo(p, PackageManager.GET_META_DATA); - final BasePermission bp; + final Permission bp; if (p.isTree()) { - bp = BasePermission.createOrUpdate( + bp = Permission.createOrUpdate( mPackageManagerInt, - mSettings.getPermissionTreeLocked(p.getName()), permissionInfo, pkg, - mSettings.getAllPermissionTreesLocked(), chatty); - mSettings.putPermissionTreeLocked(p.getName(), bp); + mRegistry.getPermissionTreeLocked(p.getName()), permissionInfo, pkg, + mRegistry.getPermissionTreesLocked(), chatty); + mRegistry.addPermissionTreeLocked(bp); } else { - bp = BasePermission.createOrUpdate( + bp = Permission.createOrUpdate( mPackageManagerInt, - mSettings.getPermissionLocked(p.getName()), - permissionInfo, pkg, mSettings.getAllPermissionTreesLocked(), chatty); - mSettings.putPermissionLocked(p.getName(), bp); + mRegistry.getPermissionLocked(p.getName()), + permissionInfo, pkg, mRegistry.getPermissionTreesLocked(), chatty); + mRegistry.addPermissionLocked(bp); } if (bp.isInstalled()) { p.setFlags(p.getFlags() | PermissionInfo.FLAG_INSTALLED); } - if (bp.isPermissionDefinitionChanged()) { + if (bp.isDefinitionChanged()) { definitionChangedPermissions.add(p.getName()); } } @@ -2444,45 +2443,46 @@ public class PermissionManagerService extends IPermissionManager.Stub { } private void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) { - final int N = ArrayUtils.size(pkg.getPermissionGroups()); - StringBuilder r = null; - for (int i=0; i<N; i++) { - final ParsedPermissionGroup pg = pkg.getPermissionGroups().get(i); - final ParsedPermissionGroup cur = mSettings.mPermissionGroups.get(pg.getName()); - final String curPackageName = (cur == null) ? null : cur.getPackageName(); - final boolean isPackageUpdate = pg.getPackageName().equals(curPackageName); - if (cur == null || isPackageUpdate) { - mSettings.mPermissionGroups.put(pg.getName(), pg); - if (chatty && DEBUG_PACKAGE_SCANNING) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - if (isPackageUpdate) { - r.append("UPD:"); + synchronized (mLock) { + final int N = ArrayUtils.size(pkg.getPermissionGroups()); + StringBuilder r = null; + for (int i = 0; i < N; i++) { + final ParsedPermissionGroup pg = pkg.getPermissionGroups().get(i); + final ParsedPermissionGroup cur = mRegistry.getPermissionGroupLocked(pg.getName()); + final String curPackageName = (cur == null) ? null : cur.getPackageName(); + final boolean isPackageUpdate = pg.getPackageName().equals(curPackageName); + if (cur == null || isPackageUpdate) { + mRegistry.addPermissionGroupLocked(pg); + if (chatty && DEBUG_PACKAGE_SCANNING) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + if (isPackageUpdate) { + r.append("UPD:"); + } + r.append(pg.getName()); } - r.append(pg.getName()); - } - } else { - Slog.w(TAG, "Permission group " + pg.getName() + " from package " - + pg.getPackageName() + " ignored: original from " - + cur.getPackageName()); - if (chatty && DEBUG_PACKAGE_SCANNING) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); + } else { + Slog.w(TAG, "Permission group " + pg.getName() + " from package " + + pg.getPackageName() + " ignored: original from " + + cur.getPackageName()); + if (chatty && DEBUG_PACKAGE_SCANNING) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append("DUP:"); + r.append(pg.getName()); } - r.append("DUP:"); - r.append(pg.getName()); } } + if (r != null && DEBUG_PACKAGE_SCANNING) { + Log.d(TAG, " Permission Groups: " + r); + } } - if (r != null && DEBUG_PACKAGE_SCANNING) { - Log.d(TAG, " Permission Groups: " + r); - } - } private void removeAllPermissions(AndroidPackage pkg, boolean chatty) { @@ -2491,9 +2491,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { StringBuilder r = null; for (int i=0; i<N; i++) { ParsedPermission p = pkg.getPermissions().get(i); - BasePermission bp = mSettings.mPermissions.get(p.getName()); + Permission bp = mRegistry.getPermissionLocked(p.getName()); if (bp == null) { - bp = mSettings.mPermissionTrees.get(p.getName()); + bp = mRegistry.getPermissionTreeLocked(p.getName()); } if (bp != null && bp.isPermission(p)) { bp.setPermissionInfo(null); @@ -2507,11 +2507,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } if (p.isAppOp()) { - ArraySet<String> appOpPkgs = - mSettings.mAppOpPermissionPackages.get(p.getName()); - if (appOpPkgs != null) { - appOpPkgs.remove(pkg.getPackageName()); - } + // TODO(zhanghai): Should we just remove the entry for this permission directly? + mRegistry.removeAppOpPermissionPackageLocked(p.getName(), pkg.getPackageName()); } } if (r != null) { @@ -2522,14 +2519,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { r = null; for (int i=0; i<N; i++) { String perm = pkg.getRequestedPermissions().get(i); - if (mSettings.isPermissionAppOp(perm)) { - ArraySet<String> appOpPkgs = mSettings.mAppOpPermissionPackages.get(perm); - if (appOpPkgs != null) { - appOpPkgs.remove(pkg.getPackageName()); - if (appOpPkgs.isEmpty()) { - mSettings.mAppOpPermissionPackages.remove(perm); - } - } + if (mRegistry.isPermissionAppOp(perm)) { + mRegistry.removeAppOpPermissionPackageLocked(perm, pkg.getPackageName()); } } if (r != null) { @@ -2567,7 +2558,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final Set<String> instantPermissions = new ArraySet<>(uidState.getGrantedPermissions()); instantPermissions.removeIf(permissionName -> { - BasePermission permission = mSettings.getPermission(permissionName); + Permission permission = mRegistry.getPermission(permissionName); if (permission == null) { return true; } @@ -2585,7 +2576,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { @NonNull private int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) { - BasePermission permission = mSettings.getPermission(permissionName); + Permission permission = mRegistry.getPermission(permissionName); if (permission == null) { return EmptyArray.INT; } @@ -2638,7 +2629,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int i = 0; i < requestedPermissionsSize; i++) { final String permissionName = pkg.getRequestedPermissions().get(i); - final BasePermission permission = mSettings.getPermission(permissionName); + final Permission permission = mRegistry.getPermission(permissionName); if (permission == null) { continue; } @@ -2683,7 +2674,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } for (String permissionName : uidRequestedPermissions) { - BasePermission permission = mSettings.getPermission(permissionName); + Permission permission = mRegistry.getPermission(permissionName); if (permission == null) { continue; } @@ -2741,7 +2732,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int i = 0; i < requestedPermissionsSize; i++) { final String permName = requestedPermissions.get(i); - final BasePermission bp = mSettings.getPermission(permName); + final Permission bp = mRegistry.getPermission(permName); final boolean appSupportsRuntimePermissions = pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; String legacyActivityRecognitionPermission = null; @@ -2834,7 +2825,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Keep track of app op permissions. if (bp.isAppOp()) { - mSettings.addAppOpPackage(perm, pkg.getPackageName()); + mRegistry.addAppOpPermissionPackageLocked(perm, pkg.getPackageName()); } boolean shouldGrantNormalPermission = true; @@ -3057,7 +3048,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (String permission : ps.getGrantedPermissions()) { if (!pkg.getImplicitPermissions().contains(permission)) { - BasePermission bp = mSettings.getPermissionLocked(permission); + Permission bp = mRegistry.getPermissionLocked(permission); if (bp != null && bp.isRuntime()) { int flags = ps.getPermissionFlags(permission); @@ -3131,11 +3122,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { + " for " + pkgName); } - ps.grantPermission(mSettings.getPermissionLocked(newPerm)); + ps.grantPermission(mRegistry.getPermissionLocked(newPerm)); } // Add permission flags - ps.updatePermissionFlags(mSettings.getPermission(newPerm), flags, flags); + ps.updatePermissionFlags(mRegistry.getPermission(newPerm), flags, flags); } /** @@ -3206,7 +3197,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArraySet<String> sourcePerms = newToSplitPerms.get(newPerm); if (sourcePerms != null) { - BasePermission bp = mSettings.getPermissionLocked(newPerm); + Permission bp = mRegistry.getPermissionLocked(newPerm); if (bp.isRuntime()) { if (!newPerm.equals(Manifest.permission.ACTIVITY_RECOGNITION)) { @@ -3221,7 +3212,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int sourcePermNum = 0; sourcePermNum < sourcePerms.size(); sourcePermNum++) { final String sourcePerm = sourcePerms.valueAt(sourcePermNum); - BasePermission sourceBp = mSettings.getPermissionLocked(sourcePerm); + Permission sourceBp = mRegistry.getPermissionLocked(sourcePerm); if (!sourceBp.isRuntime()) { inheritsFromInstallPerm = true; break; @@ -3344,7 +3335,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } private boolean shouldGrantSignaturePermission(@NonNull AndroidPackage pkg, - @NonNull PackageSetting pkgSetting, @NonNull BasePermission bp) { + @NonNull PackageSetting pkgSetting, @NonNull Permission bp) { // expect single system package String systemPackageName = ArrayUtils.firstOrNull(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM)); @@ -3510,7 +3501,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { @NonNull private PackageParser.SigningDetails getSourcePackageSigningDetails( - @NonNull BasePermission bp) { + @NonNull Permission bp) { final PackageSetting ps = getSourcePackageSetting(bp); if (ps == null) { return PackageParser.SigningDetails.UNKNOWN; @@ -3519,13 +3510,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Nullable - private PackageSetting getSourcePackageSetting(@NonNull BasePermission bp) { + private PackageSetting getSourcePackageSetting(@NonNull Permission bp) { final String sourcePackageName = bp.getPackageName(); return mPackageManagerInt.getPackageSetting(sourcePackageName); } private boolean canGrantPrivilegedPermission(@NonNull AndroidPackage pkg, - boolean isUpdatedSystemApp, @NonNull BasePermission permission) { + boolean isUpdatedSystemApp, @NonNull Permission permission) { if (!pkg.isPrivileged()) { return false; } @@ -3671,9 +3662,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.getPackageName(), userId); for (String permission : pkg.getRequestedPermissions()) { - final BasePermission bp; + final Permission bp; synchronized (mLock) { - bp = mSettings.getPermissionLocked(permission); + bp = mRegistry.getPermissionLocked(permission); } if (bp != null && (bp.isRuntime() || bp.isDevelopment()) && (!instantApp || bp.isInstant()) @@ -3713,7 +3704,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int j = 0; j < permissionCount; j++) { final String permissionName = pkg.getRequestedPermissions().get(j); - final BasePermission bp = mSettings.getPermissionLocked(permissionName); + final Permission bp = mRegistry.getPermissionLocked(permissionName); if (bp == null || !bp.isHardOrSoftRestricted()) { continue; @@ -3874,7 +3865,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { int affectedUserId = UserHandle.USER_NULL; // Update permissions for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) { - BasePermission bp = mSettings.getPermission(eachPerm); + Permission bp = mRegistry.getPermission(eachPerm); if (bp == null) { continue; } @@ -3948,7 +3939,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int requestedPermCount = pkg.getRequestedPermissions().size(); for (int j = 0; j < requestedPermCount; j++) { String permission = pkg.getRequestedPermissions().get(j); - BasePermission bp = mSettings.getPermissionLocked(permission); + Permission bp = mRegistry.getPermissionLocked(permission); if (bp != null) { usedPermissions.add(permission); } @@ -3963,7 +3954,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int i = permissionStatesSize - 1; i >= 0; i--) { PermissionState permissionState = permissionStates.get(i); if (!usedPermissions.contains(permissionState.getName())) { - BasePermission bp = mSettings.getPermissionLocked(permissionState.getName()); + Permission bp = mRegistry.getPermissionLocked(permissionState.getName()); if (bp != null) { if (uidState.removePermissionState(bp.getName()) && permissionState.isRuntime()) { @@ -4036,7 +4027,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Cache background -> foreground permission mapping. // Only system declares background permissions, hence mapping does never change. mBackgroundPermissions = new ArrayMap<>(); - for (BasePermission bp : mSettings.getAllPermissionsLocked()) { + for (Permission bp : mRegistry.getPermissionsLocked()) { if (bp.getBackgroundPermission() != null) { String fgPerm = bp.getName(); String bgPerm = bp.getBackgroundPermission(); @@ -4180,13 +4171,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { } boolean changed = false; - Set<BasePermission> needsUpdate = null; + Set<Permission> needsUpdate = null; synchronized (mLock) { - final Iterator<BasePermission> it = mSettings.mPermissions.values().iterator(); - while (it.hasNext()) { - final BasePermission bp = it.next(); + for (final Permission bp : mRegistry.getPermissionsLocked()) { if (bp.isDynamic()) { - bp.updateDynamicPermission(mSettings.mPermissionTrees.values()); + bp.updateDynamicPermission(mRegistry.getPermissionTreesLocked()); } if (!packageName.equals(bp.getPackageName())) { // Not checking sourcePackageSetting because it can be null when @@ -4198,13 +4187,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Set to changed for either install or uninstall changed = true; if (needsUpdate == null) { - needsUpdate = new ArraySet<>(mSettings.mPermissions.size()); + needsUpdate = new ArraySet<>(); } needsUpdate.add(bp); } } if (needsUpdate != null) { - for (final BasePermission bp : needsUpdate) { + for (final Permission bp : needsUpdate) { // If the target package is being uninstalled, we need to revoke this permission // From all other packages if (pkg == null || !hasPermission(pkg, bp.getName())) { @@ -4236,7 +4225,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } }); } - mSettings.removePermissionLocked(bp.getName()); + mRegistry.removePermissionLocked(bp.getName()); continue; } final AndroidPackage sourcePkg = @@ -4250,7 +4239,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } Slog.w(TAG, "Removing dangling permission: " + bp.getName() + " from package " + bp.getPackageName()); - mSettings.removePermissionLocked(bp.getName()); + mRegistry.removePermissionLocked(bp.getName()); } } } @@ -4316,11 +4305,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { } boolean changed = false; - Set<BasePermission> needsUpdate = null; + Set<Permission> needsUpdate = null; synchronized (mLock) { - final Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator(); + final Iterator<Permission> it = mRegistry.getPermissionTreesLocked().iterator(); while (it.hasNext()) { - final BasePermission bp = it.next(); + final Permission bp = it.next(); if (!packageName.equals(bp.getPackageName())) { // Not checking sourcePackageSetting because it can be null when // the permission source package is the target package and the target package is @@ -4336,13 +4325,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { it.remove(); } if (needsUpdate == null) { - needsUpdate = new ArraySet<>(mSettings.mPermissionTrees.size()); + needsUpdate = new ArraySet<>(); } needsUpdate.add(bp); } } if (needsUpdate != null) { - for (final BasePermission bp : needsUpdate) { + for (final Permission bp : needsUpdate) { final AndroidPackage sourcePkg = mPackageManagerInt.getPackage(bp.getPackageName()); final PackageSetting sourcePs = @@ -4354,7 +4343,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } Slog.w(TAG, "Removing dangling permission tree: " + bp.getName() + " from package " + bp.getPackageName()); - mSettings.removePermissionLocked(bp.getName()); + mRegistry.removePermissionLocked(bp.getName()); } } } @@ -4536,16 +4525,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @GuardedBy({"mSettings.mLock", "mLock"}) - private int calculateCurrentPermissionFootprintLocked(BasePermission tree) { + private int calculateCurrentPermissionFootprintLocked(@NonNull Permission permissionTree) { int size = 0; - for (BasePermission perm : mSettings.mPermissions.values()) { - size += tree.calculateFootprint(perm); + for (final Permission permission : mRegistry.getPermissionsLocked()) { + size += permissionTree.calculateFootprint(permission); } return size; } @GuardedBy({"mSettings.mLock", "mLock"}) - private void enforcePermissionCapLocked(PermissionInfo info, BasePermission tree) { + private void enforcePermissionCapLocked(PermissionInfo info, Permission tree) { // We calculate the max size of permissions defined by this uid and throw // if that plus the size of 'info' would exceed our stated maximum. if (tree.getUid() != Process.SYSTEM_UID) { @@ -4670,7 +4659,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - private void readStateFromPackageSettings() { + private void readLegacyPermissionState() { final int[] userIds = getAllUserIds(); mPackageManagerInt.forEachPackageSetting(ps -> { final int appId = ps.getAppId(); @@ -4684,24 +4673,30 @@ public class PermissionManagerService extends IPermissionManager.Stub { final UidPermissionState uidState = userState.getOrCreateUidState(appId); uidState.reset(); uidState.setMissing(legacyState.isMissing(userId)); - readStateFromPermissionStates(uidState, + readLegacyPermissionStatesLocked(uidState, legacyState.getInstallPermissionStates()); - readStateFromPermissionStates(uidState, + readLegacyPermissionStatesLocked(uidState, legacyState.getRuntimePermissionStates(userId)); } } }); } - private void readStateFromPermissionStates(@NonNull UidPermissionState uidState, + private void readLegacyPermissionStatesLocked(@NonNull UidPermissionState uidState, @NonNull Collection<LegacyPermissionState.PermissionState> permissionStates) { for (final LegacyPermissionState.PermissionState permissionState : permissionStates) { - uidState.putPermissionState(permissionState.getPermission(), - permissionState.isGranted(), permissionState.getFlags()); + final String permissionName = permissionState.getName(); + final Permission permission = mRegistry.getPermissionLocked(permissionName); + if (permission == null) { + Slog.w(TAG, "Unknown permission: " + permissionName); + continue; + } + uidState.putPermissionState(permission, permissionState.isGranted(), + permissionState.getFlags()); } } - private void writeStateToPackageSettings() { + private void writeLegacyPermissionState() { final int[] userIds; synchronized (mLock) { userIds = mState.getUserIds(); @@ -4738,12 +4733,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { final PermissionState permissionState = permissionStates.get(i); final LegacyPermissionState.PermissionState legacyPermissionState = - new LegacyPermissionState.PermissionState( - permissionState.getPermission(), + new LegacyPermissionState.PermissionState(permissionState.getName(), permissionState.isGranted(), permissionState.getFlags()); if (permissionState.isRuntime()) { - legacyState.putRuntimePermissionState(legacyPermissionState, - userId); + legacyState.putRuntimePermissionState(legacyPermissionState, userId); } else { legacyState.putInstallPermissionState(legacyPermissionState); } @@ -4753,6 +4746,108 @@ public class PermissionManagerService extends IPermissionManager.Stub { }); } + private void readLegacyPermissions(@NonNull LegacyPermissionSettings legacyPermissionSettings) { + for (int readPermissionOrPermissionTree = 0; readPermissionOrPermissionTree < 2; + readPermissionOrPermissionTree++) { + final List<LegacyPermission> legacyPermissions = readPermissionOrPermissionTree == 0 + ? legacyPermissionSettings.getPermissions() + : legacyPermissionSettings.getPermissionTrees(); + synchronized (mLock) { + final int legacyPermissionsSize = legacyPermissions.size(); + for (int i = 0; i < legacyPermissionsSize; i++) { + final LegacyPermission legacyPermission = legacyPermissions.get(i); + final Permission permission = new Permission( + legacyPermission.getPermissionInfo(), legacyPermission.getType()); + if (readPermissionOrPermissionTree == 0) { + // Config permissions are currently read in PermissionManagerService + // constructor. The old behavior was to add other attributes to the config + // permission in LegacyPermission.read(), so equivalently we can add the + // GIDs to the new permissions here, since config permissions created in + // PermissionManagerService constructor get only their names and GIDs there. + final Permission configPermission = mRegistry.getPermission( + permission.getName()); + if (configPermission != null + && configPermission.getType() == Permission.TYPE_CONFIG) { + permission.setGids(configPermission.getRawGids(), + configPermission.areGidsPerUser()); + } + mRegistry.addPermissionLocked(permission); + } else { + mRegistry.addPermissionTreeLocked(permission); + } + } + } + } + } + + private void writeLegacyPermissions( + @NonNull LegacyPermissionSettings legacyPermissionSettings) { + for (int writePermissionOrPermissionTree = 0; writePermissionOrPermissionTree < 2; + writePermissionOrPermissionTree++) { + final List<LegacyPermission> legacyPermissions = new ArrayList<>(); + synchronized (mLock) { + final Collection<Permission> permissions = writePermissionOrPermissionTree == 0 + ? mRegistry.getPermissionsLocked() : mRegistry.getPermissionTreesLocked(); + for (final Permission permission : permissions) { + // We don't need to provide UID and GIDs, which are only retrieved when dumping. + final LegacyPermission legacyPermission = new LegacyPermission( + permission.getPermissionInfo(), permission.getType(), 0, + EmptyArray.INT); + legacyPermissions.add(legacyPermission); + } + } + if (writePermissionOrPermissionTree == 0) { + legacyPermissionSettings.replacePermissions(legacyPermissions); + } else { + legacyPermissionSettings.replacePermissionTrees(legacyPermissions); + } + } + } + + private void transferPermissions(@NonNull String oldPackageName, + @NonNull String newPackageName) { + synchronized (mLock) { + mRegistry.transferPermissionsLocked(oldPackageName, newPackageName); + } + } + + private boolean canPropagatePermissionToInstantApp(@NonNull String permissionName) { + synchronized (mLock) { + final Permission bp = mRegistry.getPermission(permissionName); + return bp != null && (bp.isRuntime() || bp.isDevelopment()) && bp.isInstant(); + } + } + + @NonNull + private List<LegacyPermission> getLegacyPermissions() { + synchronized (mLock) { + final List<LegacyPermission> legacyPermissions = new ArrayList<>(); + for (final Permission permission : mRegistry.getPermissionsLocked()) { + final LegacyPermission legacyPermission = new LegacyPermission( + permission.getPermissionInfo(), permission.getType(), permission.getUid(), + permission.getRawGids()); + legacyPermissions.add(legacyPermission); + } + return legacyPermissions; + } + } + + @NonNull + private Map<String, Set<String>> getAllAppOpPermissionPackages() { + synchronized (mLock) { + final ArrayMap<String, ArraySet<String>> appOpPermissionPackages = + mRegistry.getAllAppOpPermissionPackagesLocked(); + final Map<String, Set<String>> deepClone = new ArrayMap<>(); + final int appOpPermissionPackagesSize = appOpPermissionPackages.size(); + for (int i = 0; i < appOpPermissionPackagesSize; i++) { + final String appOpPermission = appOpPermissionPackages.keyAt(i); + final ArraySet<String> packageNames = appOpPermissionPackages.valueAt(i); + deepClone.put(appOpPermission, new ArraySet<>(packageNames)); + } + return deepClone; + } + } + @NonNull private LegacyPermissionState getLegacyPermissionState(@AppIdInt int appId) { final LegacyPermissionState legacyState = new LegacyPermissionState(); @@ -4772,9 +4867,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { final PermissionState permissionState = permissionStates.get(i); final LegacyPermissionState.PermissionState legacyPermissionState = - new LegacyPermissionState.PermissionState( - permissionState.getPermission(), permissionState.isGranted(), - permissionState.getFlags()); + new LegacyPermissionState.PermissionState(permissionState.getName(), + permissionState.isGranted(), permissionState.getFlags()); if (permissionState.isRuntime()) { legacyState.putRuntimePermissionState(legacyPermissionState, userId); } else if (userId == UserHandle.USER_SYSTEM) { @@ -4842,12 +4936,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { PermissionManagerService.this.removeAllPermissions(pkg, chatty); } @Override - public void readStateFromPackageSettingsTEMP() { - PermissionManagerService.this.readStateFromPackageSettings(); + public void readLegacyPermissionStateTEMP() { + PermissionManagerService.this.readLegacyPermissionState(); } @Override - public void writeStateToPackageSettingsTEMP() { - PermissionManagerService.this.writeStateToPackageSettings(); + public void writeLegacyPermissionStateTEMP() { + PermissionManagerService.this.writeLegacyPermissionState(); } @Override public void onUserRemoved(@UserIdInt int userId) { @@ -4950,17 +5044,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Override - public void enforceGrantRevokeRuntimePermissionPermissions(String message) { - PermissionManagerService.this.enforceGrantRevokeRuntimePermissionPermissions(message); - } - @Override - public PermissionSettings getPermissionSettings() { - return mSettings; - } - @Override - public BasePermission getPermissionTEMP(String permName) { + public Permission getPermissionTEMP(String permName) { synchronized (PermissionManagerService.this.mLock) { - return mSettings.getPermissionLocked(permName); + return mRegistry.getPermissionLocked(permName); } } @@ -4970,13 +5056,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>(); synchronized (mLock) { - int numTotalPermissions = mSettings.mPermissions.size(); - - for (int i = 0; i < numTotalPermissions; i++) { - BasePermission bp = mSettings.mPermissions.valueAt(i); - - if (bp.getProtection() == protection) { - matchingPermissions.add(bp.generatePermissionInfo(0)); + for (final Permission permission : mRegistry.getPermissionsLocked()) { + if (permission.getProtection() == protection) { + matchingPermissions.add(permission.generatePermissionInfo(0)); } } } @@ -4990,13 +5072,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>(); synchronized (mLock) { - int numTotalPermissions = mSettings.mPermissions.size(); - - for (int i = 0; i < numTotalPermissions; i++) { - BasePermission bp = mSettings.mPermissions.valueAt(i); - - if ((bp.getProtectionFlags() & protectionFlags) == protectionFlags) { - matchingPermissions.add(bp.generatePermissionInfo(0)); + for (final Permission permission : mRegistry.getPermissionsLocked()) { + if ((permission.getProtectionFlags() & protectionFlags) == protectionFlags) { + matchingPermissions.add(permission.generatePermissionInfo(0)); } } } @@ -5187,25 +5265,62 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Override - public void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissions) { + public void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissionNames) { synchronized (mLock) { - Iterator<String> iterator = permissions.iterator(); + Iterator<String> iterator = permissionNames.iterator(); while (iterator.hasNext()) { - String permission = iterator.next(); - BasePermission basePermission = mSettings.mPermissions.get(permission); - if (basePermission == null || !basePermission.isHardOrSoftRestricted()) { + final String permissionName = iterator.next(); + final Permission permission = mRegistry.getPermissionLocked(permissionName); + if (permission == null || !permission.isHardOrSoftRestricted()) { iterator.remove(); } } } } + @Override + public void readLegacyPermissionsTEMP( + @NonNull LegacyPermissionSettings legacyPermissionSettings) { + PermissionManagerService.this.readLegacyPermissions(legacyPermissionSettings); + } + + @Override + public void writeLegacyPermissionsTEMP( + @NonNull LegacyPermissionSettings legacyPermissionSettings) { + PermissionManagerService.this.writeLegacyPermissions(legacyPermissionSettings); + } + + @Override + public void transferPermissions(@NonNull String oldPackageName, + @NonNull String newPackageName) { + PermissionManagerService.this.transferPermissions(oldPackageName, newPackageName); + } + + @Override + public boolean canPropagatePermissionToInstantApp(@NonNull String permissionName) { + return PermissionManagerService.this.canPropagatePermissionToInstantApp(permissionName); + } + + @NonNull + @Override + public List<LegacyPermission> getLegacyPermissions() { + return PermissionManagerService.this.getLegacyPermissions(); + } + @NonNull + @Override + public Map<String, Set<String>> getAllAppOpPermissionPackages() { + return PermissionManagerService.this.getAllAppOpPermissionPackages(); + } + + @NonNull + @Override public LegacyPermissionState getLegacyPermissionState(@AppIdInt int appId) { return PermissionManagerService.this.getLegacyPermissionState(appId); } @NonNull + @Override public int[] getGidsForUid(int uid) { return PermissionManagerService.this.getGidsForUid(uid); } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index 20e9c5dcb521..df81bac99a21 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -280,21 +280,21 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); /** - * Read permission state from package settings. + * Read legacy permission state from package settings. * * TODO(zhanghai): This is a temporary method because we should not expose * {@code PackageSetting} which is a implementation detail that permission should not know. * Instead, it should retrieve the legacy state via a defined API. */ - public abstract void readStateFromPackageSettingsTEMP(); + public abstract void readLegacyPermissionStateTEMP(); /** - * Write permission state to package settings. + * Write legacy permission state to package settings. * * TODO(zhanghai): This is a temporary method and should be removed once we migrated persistence * for permission. */ - public abstract void writeStateToPackageSettingsTEMP(); + public abstract void writeLegacyPermissionStateTEMP(); /** * Notify that a user has been removed and its permission state should be removed as well. @@ -367,16 +367,14 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager public abstract void enforceCrossUserPermission(int callingUid, int userId, boolean requireFullPermission, boolean checkShell, boolean requirePermissionWhenSameUser, @NonNull String message); - public abstract void enforceGrantRevokeRuntimePermissionPermissions(@NonNull String message); - - public abstract @NonNull PermissionSettings getPermissionSettings(); /** Grants default browser permissions to the given package */ public abstract void grantDefaultPermissionsToDefaultBrowser( @NonNull String packageName, @UserIdInt int userId); /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */ - public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName); + @Nullable + public abstract Permission getPermissionTEMP(@NonNull String permName); /** Get all permissions that have a certain protection */ public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtection( @@ -536,5 +534,39 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager * Removes invalid permissions which are not {@link PermissionInfo#FLAG_HARD_RESTRICTED} or * {@link PermissionInfo#FLAG_SOFT_RESTRICTED} from the input. */ - public abstract void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissions); + public abstract void retainHardAndSoftRestrictedPermissions( + @NonNull List<String> permissionNames); + + /** + * Read legacy permissions from legacy permission settings. + * + * TODO(zhanghai): This is a temporary method because we should not expose + * {@code LegacyPermissionSettings} which is a implementation detail that permission should not + * know. Instead, it should retrieve the legacy permissions via a defined API. + */ + public abstract void readLegacyPermissionsTEMP( + @NonNull LegacyPermissionSettings legacyPermissionSettings); + + /** + * Write legacy permissions to legacy permission settings. + * + * TODO(zhanghai): This is a temporary method and should be removed once we migrated persistence + * for permission. + */ + public abstract void writeLegacyPermissionsTEMP( + @NonNull LegacyPermissionSettings legacyPermissionSettings); + + /** + * Transfers ownership of permissions from one package to another. + */ + public abstract void transferPermissions(@NonNull String oldPackageName, + @NonNull String newPackageName); + + /** + * Check whether a permission can be propagated to instant app. + * + * @param permissionName the name of the permission + * @return whether the permission can be propagated + */ + public abstract boolean canPropagatePermissionToInstantApp(@NonNull String permissionName); } diff --git a/services/core/java/com/android/server/pm/permission/PermissionRegistry.java b/services/core/java/com/android/server/pm/permission/PermissionRegistry.java new file mode 100644 index 000000000000..36719203e4b5 --- /dev/null +++ b/services/core/java/com/android/server/pm/permission/PermissionRegistry.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2017 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.NonNull; +import android.annotation.Nullable; +import android.content.pm.parsing.component.ParsedPermissionGroup; +import android.util.ArrayMap; +import android.util.ArraySet; + +import com.android.internal.annotations.GuardedBy; + +import java.util.Collection; + +/** + * Permission registry for permissions, permission trees, permission groups and related things. + */ +public class PermissionRegistry { + /** + * All of the permissions known to the system. The mapping is from permission + * name to permission object. + */ + @GuardedBy("mLock") + private final ArrayMap<String, Permission> mPermissions = new ArrayMap<>(); + + /** + * All permission trees known to the system. The mapping is from permission tree + * name to permission object. + */ + @GuardedBy("mLock") + private final ArrayMap<String, Permission> mPermissionTrees = new ArrayMap<>(); + + /** + * All permisson groups know to the system. The mapping is from permission group + * name to permission group object. + */ + @GuardedBy("mLock") + private final ArrayMap<String, ParsedPermissionGroup> mPermissionGroups = new ArrayMap<>(); + + /** + * Set of packages that request a particular app op. The mapping is from permission + * name to package names. + */ + @GuardedBy("mLock") + private final ArrayMap<String, ArraySet<String>> mAppOpPermissionPackages = new ArrayMap<>(); + + @NonNull + private final Object mLock; + + public PermissionRegistry(@NonNull Object lock) { + mLock = lock; + } + + @GuardedBy("mLock") + @NonNull + public Collection<Permission> getPermissionsLocked() { + return mPermissions.values(); + } + + @GuardedBy("mLock") + @Nullable + public Permission getPermissionLocked(@NonNull String permName) { + return mPermissions.get(permName); + } + + @Nullable + public Permission getPermission(@NonNull String permissionName) { + synchronized (mLock) { + return getPermissionLocked(permissionName); + } + } + + @GuardedBy("mLock") + public void addPermissionLocked(@NonNull Permission permission) { + mPermissions.put(permission.getName(), permission); + } + + @GuardedBy("mLock") + public void removePermissionLocked(@NonNull String permissionName) { + mPermissions.remove(permissionName); + } + + @GuardedBy("mLock") + @NonNull + public Collection<Permission> getPermissionTreesLocked() { + return mPermissionTrees.values(); + } + + @GuardedBy("mLock") + @Nullable + public Permission getPermissionTreeLocked(@NonNull String permissionTreeName) { + return mPermissionTrees.get(permissionTreeName); + } + + @GuardedBy("mLock") + public void addPermissionTreeLocked(@NonNull Permission permissionTree) { + mPermissionTrees.put(permissionTree.getName(), permissionTree); + } + + /** + * Transfers ownership of permissions from one package to another. + */ + public void transferPermissionsLocked(@NonNull String oldPackageName, + @NonNull String newPackageName) { + for (int i = 0; i < 2; i++) { + ArrayMap<String, Permission> permissions = i == 0 ? mPermissionTrees : mPermissions; + for (final Permission permission : permissions.values()) { + permission.transfer(oldPackageName, newPackageName); + } + } + } + + @GuardedBy("mLock") + @NonNull + public Collection<ParsedPermissionGroup> getPermissionGroupsLocked() { + return mPermissionGroups.values(); + } + + @GuardedBy("mLock") + @Nullable + public ParsedPermissionGroup getPermissionGroupLocked(@NonNull String permissionGroupName) { + return mPermissionGroups.get(permissionGroupName); + } + + @GuardedBy("mLock") + public void addPermissionGroupLocked(@NonNull ParsedPermissionGroup permissionGroup) { + mPermissionGroups.put(permissionGroup.getName(), permissionGroup); + } + + @GuardedBy("mLock") + @NonNull + public ArrayMap<String, ArraySet<String>> getAllAppOpPermissionPackagesLocked() { + return mAppOpPermissionPackages; + } + + @GuardedBy("mLock") + @Nullable + public ArraySet<String> getAppOpPermissionPackagesLocked(@NonNull String permissionName) { + return mAppOpPermissionPackages.get(permissionName); + } + + @GuardedBy("mLock") + public void addAppOpPermissionPackageLocked(@NonNull String permissionName, + @NonNull String packageName) { + ArraySet<String> packageNames = mAppOpPermissionPackages.get(permissionName); + if (packageNames == null) { + packageNames = new ArraySet<>(); + mAppOpPermissionPackages.put(permissionName, packageNames); + } + packageNames.add(packageName); + } + + @GuardedBy("mLock") + public void removeAppOpPermissionPackageLocked(@NonNull String permissionName, + @NonNull String packageName) { + final ArraySet<String> packageNames = mAppOpPermissionPackages.get(permissionName); + if (packageNames == null) { + return; + } + final boolean removed = packageNames.remove(packageName); + if (removed && packageNames.isEmpty()) { + mAppOpPermissionPackages.remove(permissionName); + } + } + + /** + * Returns the permission tree for the given permission. + * @throws SecurityException If the calling UID is not allowed to add permissions to the + * found permission tree. + */ + @NonNull + public Permission enforcePermissionTree(@NonNull String permissionName, int callingUid) { + synchronized (mLock) { + return Permission.enforcePermissionTree(mPermissionTrees.values(), permissionName, + callingUid); + } + } + + public boolean isPermissionInstant(@NonNull String permissionName) { + synchronized (mLock) { + final Permission permission = mPermissions.get(permissionName); + return permission != null && permission.isInstant(); + } + } + + boolean isPermissionAppOp(@NonNull String permissionName) { + synchronized (mLock) { + final Permission permission = mPermissions.get(permissionName); + return permission != null && permission.isAppOp(); + } + } +} diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java deleted file mode 100644 index eea8ac737b86..000000000000 --- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2017 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.NonNull; -import android.annotation.Nullable; -import android.content.pm.parsing.component.ParsedPermissionGroup; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Log; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.XmlUtils; -import com.android.server.pm.DumpState; -import com.android.server.pm.PackageManagerService; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Collection; - -/** - * Permissions and other related data. This class is not meant for - * direct access outside of the permission package with the sole exception - * of package settings. Instead, it should be reference either from the - * permission manager or package settings. - */ -public class PermissionSettings { - - /** - * All of the permissions known to the system. The mapping is from permission - * name to permission object. - */ - @GuardedBy("mLock") - final ArrayMap<String, BasePermission> mPermissions = - new ArrayMap<String, BasePermission>(); - - /** - * All permission trees known to the system. The mapping is from permission tree - * name to permission object. - */ - @GuardedBy("mLock") - final ArrayMap<String, BasePermission> mPermissionTrees = - new ArrayMap<String, BasePermission>(); - - /** - * All permisson groups know to the system. The mapping is from permission group - * name to permission group object. - */ - @GuardedBy("mLock") - final ArrayMap<String, ParsedPermissionGroup> mPermissionGroups = - new ArrayMap<>(); - - /** - * Set of packages that request a particular app op. The mapping is from permission - * name to package names. - */ - @GuardedBy("mLock") - final ArrayMap<String, ArraySet<String>> mAppOpPermissionPackages = new ArrayMap<>(); - - private final Object mLock; - - PermissionSettings(@NonNull Object lock) { - mLock = lock; - } - - public @Nullable BasePermission getPermission(@NonNull String permName) { - synchronized (mLock) { - return getPermissionLocked(permName); - } - } - - public void addAppOpPackage(String permName, String packageName) { - synchronized (mLock) { - ArraySet<String> pkgs = mAppOpPermissionPackages.get(permName); - if (pkgs == null) { - pkgs = new ArraySet<>(); - mAppOpPermissionPackages.put(permName, pkgs); - } - pkgs.add(packageName); - } - } - - /** - * Transfers ownership of permissions from one package to another. - */ - public void transferPermissions(String origPackageName, String newPackageName) { - synchronized (mLock) { - for (int i=0; i<2; i++) { - ArrayMap<String, BasePermission> permissions = - i == 0 ? mPermissionTrees : mPermissions; - for (BasePermission bp : permissions.values()) { - bp.transfer(origPackageName, newPackageName); - } - } - } - } - - public boolean canPropagatePermissionToInstantApp(String permName) { - synchronized (mLock) { - final BasePermission bp = mPermissions.get(permName); - return (bp != null && (bp.isRuntime() || bp.isDevelopment()) && bp.isInstant()); - } - } - - public void readPermissions(XmlPullParser parser) throws IOException, XmlPullParserException { - synchronized (mLock) { - readPermissions(mPermissions, parser); - } - } - - public void readPermissionTrees(XmlPullParser parser) - throws IOException, XmlPullParserException { - synchronized (mLock) { - readPermissions(mPermissionTrees, parser); - } - } - - public void writePermissions(XmlSerializer serializer) throws IOException { - synchronized (mLock) { - for (BasePermission bp : mPermissions.values()) { - bp.writeLPr(serializer); - } - } - } - - public void writePermissionTrees(XmlSerializer serializer) throws IOException { - synchronized (mLock) { - for (BasePermission bp : mPermissionTrees.values()) { - bp.writeLPr(serializer); - } - } - } - - public static void readPermissions(ArrayMap<String, BasePermission> out, XmlPullParser parser) - throws IOException, XmlPullParserException { - int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - if (!BasePermission.readLPw(out, parser)) { - PackageManagerService.reportSettingsProblem(Log.WARN, - "Unknown element reading permissions: " + parser.getName() + " at " - + parser.getPositionDescription()); - } - XmlUtils.skipCurrentTag(parser); - } - } - - public void dumpPermissions(PrintWriter pw, String packageName, - ArraySet<String> permissionNames, boolean externalStorageEnforced, - DumpState dumpState) { - synchronized (mLock) { - boolean printedSomething = false; - for (BasePermission bp : mPermissions.values()) { - printedSomething = bp.dumpPermissionsLPr(pw, packageName, permissionNames, - externalStorageEnforced, printedSomething, dumpState); - } - if (packageName == null && permissionNames == null) { - for (int iperm = 0; iperm<mAppOpPermissionPackages.size(); iperm++) { - if (iperm == 0) { - if (dumpState.onTitlePrinted()) - pw.println(); - pw.println("AppOp Permissions:"); - } - pw.print(" AppOp Permission "); - pw.print(mAppOpPermissionPackages.keyAt(iperm)); - pw.println(":"); - ArraySet<String> pkgs = mAppOpPermissionPackages.valueAt(iperm); - for (int ipkg=0; ipkg<pkgs.size(); ipkg++) { - pw.print(" "); pw.println(pkgs.valueAt(ipkg)); - } - } - } - } - } - - @GuardedBy("mLock") - @Nullable BasePermission getPermissionLocked(@NonNull String permName) { - return mPermissions.get(permName); - } - - @GuardedBy("mLock") - @Nullable BasePermission getPermissionTreeLocked(@NonNull String permName) { - return mPermissionTrees.get(permName); - } - - @GuardedBy("mLock") - void putPermissionLocked(@NonNull String permName, @NonNull BasePermission permission) { - mPermissions.put(permName, permission); - } - - @GuardedBy("mLock") - void putPermissionTreeLocked(@NonNull String permName, @NonNull BasePermission permission) { - mPermissionTrees.put(permName, permission); - } - - @GuardedBy("mLock") - void removePermissionLocked(@NonNull String permName) { - mPermissions.remove(permName); - } - - @GuardedBy("mLock") - void removePermissionTreeLocked(@NonNull String permName) { - mPermissionTrees.remove(permName); - } - - @GuardedBy("mLock") - @NonNull Collection<BasePermission> getAllPermissionsLocked() { - return mPermissions.values(); - } - - @GuardedBy("mLock") - @NonNull Collection<BasePermission> getAllPermissionTreesLocked() { - return mPermissionTrees.values(); - } - - /** - * Returns the permission tree for the given permission. - * @throws SecurityException If the calling UID is not allowed to add permissions to the - * found permission tree. - */ - @Nullable BasePermission enforcePermissionTree(@NonNull String permName, int callingUid) { - synchronized (mLock) { - return BasePermission.enforcePermissionTree( - mPermissionTrees.values(), permName, callingUid); - } - } - - /** - * Check whether a permission is runtime. - * - * @see BasePermission#isRuntime() - */ - public boolean isPermissionRuntime(@NonNull String permName) { - synchronized (mLock) { - final BasePermission bp = mPermissions.get(permName); - return (bp != null && bp.isRuntime()); - } - } - - public boolean isPermissionInstant(String permName) { - synchronized (mLock) { - final BasePermission bp = mPermissions.get(permName); - return (bp != null && bp.isInstant()); - } - } - - boolean isPermissionAppOp(String permName) { - synchronized (mLock) { - final BasePermission bp = mPermissions.get(permName); - return (bp != null && bp.isAppOp()); - } - } - -} diff --git a/services/core/java/com/android/server/pm/permission/PermissionState.java b/services/core/java/com/android/server/pm/permission/PermissionState.java index 59b204f7dfff..12f29d091134 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionState.java +++ b/services/core/java/com/android/server/pm/permission/PermissionState.java @@ -27,7 +27,7 @@ import com.android.internal.annotations.GuardedBy; public final class PermissionState { @NonNull - private final BasePermission mPermission; + private final Permission mPermission; private final Object mLock = new Object(); @@ -40,7 +40,7 @@ public final class PermissionState { @GuardedBy("mLock") private int mFlags; - public PermissionState(@NonNull BasePermission permission) { + public PermissionState(@NonNull Permission permission) { mPermission = permission; } @@ -52,7 +52,7 @@ public final class PermissionState { } @NonNull - public BasePermission getPermission() { + public Permission getPermission() { return mPermission; } diff --git a/services/core/java/com/android/server/pm/permission/UidPermissionState.java b/services/core/java/com/android/server/pm/permission/UidPermissionState.java index 9727a5452440..04d82e872ae6 100644 --- a/services/core/java/com/android/server/pm/permission/UidPermissionState.java +++ b/services/core/java/com/android/server/pm/permission/UidPermissionState.java @@ -125,7 +125,7 @@ public final class UidPermissionState { } @NonNull - private PermissionState getOrCreatePermissionState(@NonNull BasePermission permission) { + private PermissionState getOrCreatePermissionState(@NonNull Permission permission) { if (mPermissions == null) { mPermissions = new ArrayMap<>(); } @@ -158,7 +158,7 @@ public final class UidPermissionState { * @param granted whether the permission is granted * @param flags the permission flags */ - public void putPermissionState(@NonNull BasePermission permission, boolean granted, int flags) { + public void putPermissionState(@NonNull Permission permission, boolean granted, int flags) { final String name = permission.getName(); if (mPermissions == null) { mPermissions = new ArrayMap<>(); @@ -230,7 +230,7 @@ public final class UidPermissionState { * @param permission the permission to grant * @return whether the permission grant state changed */ - public boolean grantPermission(@NonNull BasePermission permission) { + public boolean grantPermission(@NonNull Permission permission) { final PermissionState permissionState = getOrCreatePermissionState(permission); return permissionState.grant(); } @@ -241,7 +241,7 @@ public final class UidPermissionState { * @param permission the permission to revoke * @return whether the permission grant state changed */ - public boolean revokePermission(@NonNull BasePermission permission) { + public boolean revokePermission(@NonNull Permission permission) { final String name = permission.getName(); final PermissionState permissionState = getPermissionState(name); if (permissionState == null) { @@ -276,7 +276,7 @@ public final class UidPermissionState { * @param flagValues the new values for the masked flags * @return whether the permission flags changed */ - public boolean updatePermissionFlags(@NonNull BasePermission permission, int flagMask, + public boolean updatePermissionFlags(@NonNull Permission permission, int flagMask, int flagValues) { if (flagMask == 0) { return false; diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 6255630712ae..95c881e1d927 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -63,7 +63,6 @@ import com.android.server.LocalServices; import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.permission.LegacyPermissionDataProvider; -import com.android.server.pm.permission.PermissionSettings; import com.google.common.truth.Truth; @@ -92,8 +91,6 @@ public class PackageManagerSettingsTests { private static final int TEST_RESOURCE_ID = 2131231283; @Mock - PermissionSettings mPermissionSettings; - @Mock RuntimePermissionsPersistence mRuntimePermissionsPersistence; @Mock LegacyPermissionDataProvider mPermissionDataProvider; @@ -117,7 +114,7 @@ public class PackageManagerSettingsTests { writeOldFiles(); final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, + Settings settings = new Settings(context.getFilesDir(), mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); verifyKeySetMetaData(settings); @@ -131,7 +128,7 @@ public class PackageManagerSettingsTests { writeOldFiles(); final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, + Settings settings = new Settings(context.getFilesDir(), mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); @@ -147,7 +144,7 @@ public class PackageManagerSettingsTests { writeOldFiles(); final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, + Settings settings = new Settings(context.getFilesDir(), mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); assertThat(settings.getPackageLPr(PACKAGE_NAME_3), is(notNullValue())); @@ -169,13 +166,13 @@ public class PackageManagerSettingsTests { writeOldFiles(); final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, + Settings settings = new Settings(context.getFilesDir(), mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); settings.writeLPr(); // Create Settings again to make it read from the new files - settings = new Settings(context.getFilesDir(), mPermissionSettings, + settings = new Settings(context.getFilesDir(), mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); @@ -199,7 +196,7 @@ public class PackageManagerSettingsTests { writePackageRestrictions_noSuspendingPackageXml(0); final Object lock = new Object(); final Context context = InstrumentationRegistry.getTargetContext(); - final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null, + final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock); settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1)); settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2)); @@ -223,7 +220,7 @@ public class PackageManagerSettingsTests { writePackageRestrictions_noSuspendParamsMapXml(0); final Object lock = new Object(); final Context context = InstrumentationRegistry.getTargetContext(); - final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null, + final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock); settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1)); settingsUnderTest.readPackageRestrictionsLPr(0); @@ -251,7 +248,7 @@ public class PackageManagerSettingsTests { @Test public void testReadWritePackageRestrictions_suspendInfo() { final Context context = InstrumentationRegistry.getTargetContext(); - final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null, + final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, new Object()); final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1); final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2); @@ -349,7 +346,7 @@ public class PackageManagerSettingsTests { @Test public void testReadWritePackageRestrictions_distractionFlags() { final Context context = InstrumentationRegistry.getTargetContext(); - final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null, + final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, new Object()); final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1); final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2); @@ -393,7 +390,7 @@ public class PackageManagerSettingsTests { public void testWriteReadUsesStaticLibraries() { final Context context = InstrumentationRegistry.getTargetContext(); final Object lock = new Object(); - final Settings settingsUnderTest = new Settings(context.getFilesDir(), mPermissionSettings, + final Settings settingsUnderTest = new Settings(context.getFilesDir(), mRuntimePermissionsPersistence, mPermissionDataProvider, lock); final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1); ps1.appId = Process.FIRST_APPLICATION_UID; @@ -469,7 +466,7 @@ public class PackageManagerSettingsTests { writeOldFiles(); final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, + Settings settings = new Settings(context.getFilesDir(), mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); @@ -642,7 +639,7 @@ public class PackageManagerSettingsTests { public void testUpdatePackageSetting03() { final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings, + final Settings testSettings01 = new Settings(context.getFilesDir(), mRuntimePermissionsPersistence, mPermissionDataProvider, lock); final SharedUserSetting testUserSetting01 = createSharedUserSetting( testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/); @@ -752,7 +749,7 @@ public class PackageManagerSettingsTests { public void testCreateNewSetting03() { final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings, + final Settings testSettings01 = new Settings(context.getFilesDir(), mRuntimePermissionsPersistence, mPermissionDataProvider, lock); final SharedUserSetting testUserSetting01 = createSharedUserSetting( testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/); |