Move BasePermission to own package
This is the first of many changes. Moving permissions to their own package.
Change-Id: I60e94e2da3c96788fc165e97e813ab5b9ee51586
Bug: 63539144
Test: Manual. Builds and runs
Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.PermissionsHostTest
Test: cts-tradefed run commandAndExit cts-dev -m CtsPermissionTestCases
Test: cts-tradefed run commandAndExit cts-dev -m CtsPermission2TestCases
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 17b4f87..b45c26c 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -318,16 +318,19 @@
return null;
}
+ @Override
public String toString() {
return "PermissionInfo{"
+ Integer.toHexString(System.identityHashCode(this))
+ " " + name + "}";
}
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel dest, int parcelableFlags) {
super.writeToParcel(dest, parcelableFlags);
dest.writeInt(protectionLevel);
@@ -338,11 +341,25 @@
TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags);
}
+ /** @hide */
+ public int calculateFootprint() {
+ int size = name.length();
+ if (nonLocalizedLabel != null) {
+ size += nonLocalizedLabel.length();
+ }
+ if (nonLocalizedDescription != null) {
+ size += nonLocalizedDescription.length();
+ }
+ return size;
+ }
+
public static final Creator<PermissionInfo> CREATOR =
new Creator<PermissionInfo>() {
+ @Override
public PermissionInfo createFromParcel(Parcel source) {
return new PermissionInfo(source);
}
+ @Override
public PermissionInfo[] newArray(int size) {
return new PermissionInfo[size];
}
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
deleted file mode 100644
index 30fda1e..0000000
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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;
-
-import android.content.pm.PackageParser;
-import android.content.pm.PermissionInfo;
-import android.os.UserHandle;
-
-final class BasePermission {
- final static int TYPE_NORMAL = 0;
-
- final static int TYPE_BUILTIN = 1;
-
- final static int TYPE_DYNAMIC = 2;
-
- final String name;
-
- String sourcePackage;
-
- PackageSettingBase packageSetting;
-
- final int type;
-
- int protectionLevel;
-
- PackageParser.Permission perm;
-
- PermissionInfo pendingInfo;
-
- /** UID that owns the definition of this permission */
- int uid;
-
- /** Additional GIDs given to apps granted this permission */
- private int[] gids;
-
- /**
- * Flag indicating that {@link #gids} should be adjusted based on the
- * {@link UserHandle} the granted app is running as.
- */
- private boolean perUser;
-
- BasePermission(String _name, String _sourcePackage, int _type) {
- name = _name;
- sourcePackage = _sourcePackage;
- type = _type;
- // Default to most conservative protection level.
- protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
- }
-
- @Override
- public String toString() {
- return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
- + "}";
- }
-
- public void setGids(int[] gids, boolean perUser) {
- this.gids = gids;
- this.perUser = perUser;
- }
-
- public int[] computeGids(int userId) {
- if (perUser) {
- final int[] userGids = new int[gids.length];
- for (int i = 0; i < gids.length; i++) {
- userGids[i] = UserHandle.getUid(userId, gids[i]);
- }
- return userGids;
- } else {
- return gids;
- }
- }
-
- public boolean isRuntime() {
- return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
- == PermissionInfo.PROTECTION_DANGEROUS;
- }
-
- public boolean isDevelopment() {
- return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
- == PermissionInfo.PROTECTION_SIGNATURE
- && (protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0;
- }
-
- public boolean isInstant() {
- return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0;
- }
-
- public boolean isRuntimeOnly() {
- return (protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
- }
-}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index a3811ba..59e243a 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -52,6 +52,8 @@
import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
+import com.android.server.pm.permission.BasePermission;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java
new file mode 100644
index 0000000..7ebef83
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DumpState.java
@@ -0,0 +1,95 @@
+/*
+ * 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;
+
+public final class DumpState {
+ public static final int DUMP_LIBS = 1 << 0;
+ public static final int DUMP_FEATURES = 1 << 1;
+ public static final int DUMP_ACTIVITY_RESOLVERS = 1 << 2;
+ public static final int DUMP_SERVICE_RESOLVERS = 1 << 3;
+ public static final int DUMP_RECEIVER_RESOLVERS = 1 << 4;
+ public static final int DUMP_CONTENT_RESOLVERS = 1 << 5;
+ public static final int DUMP_PERMISSIONS = 1 << 6;
+ public static final int DUMP_PACKAGES = 1 << 7;
+ public static final int DUMP_SHARED_USERS = 1 << 8;
+ public static final int DUMP_MESSAGES = 1 << 9;
+ public static final int DUMP_PROVIDERS = 1 << 10;
+ public static final int DUMP_VERIFIERS = 1 << 11;
+ public static final int DUMP_PREFERRED = 1 << 12;
+ public static final int DUMP_PREFERRED_XML = 1 << 13;
+ public static final int DUMP_KEYSETS = 1 << 14;
+ public static final int DUMP_VERSION = 1 << 15;
+ public static final int DUMP_INSTALLS = 1 << 16;
+ public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 17;
+ public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
+ public static final int DUMP_FROZEN = 1 << 19;
+ public static final int DUMP_DEXOPT = 1 << 20;
+ public static final int DUMP_COMPILER_STATS = 1 << 21;
+ public static final int DUMP_CHANGES = 1 << 22;
+ public static final int DUMP_VOLUMES = 1 << 23;
+
+ public static final int OPTION_SHOW_FILTERS = 1 << 0;
+
+ private int mTypes;
+
+ private int mOptions;
+
+ private boolean mTitlePrinted;
+
+ private SharedUserSetting mSharedUser;
+
+ public boolean isDumping(int type) {
+ if (mTypes == 0 && type != DUMP_PREFERRED_XML) {
+ return true;
+ }
+
+ return (mTypes & type) != 0;
+ }
+
+ public void setDump(int type) {
+ mTypes |= type;
+ }
+
+ public boolean isOptionEnabled(int option) {
+ return (mOptions & option) != 0;
+ }
+
+ public void setOptionEnabled(int option) {
+ mOptions |= option;
+ }
+
+ public boolean onTitlePrinted() {
+ final boolean printed = mTitlePrinted;
+ mTitlePrinted = true;
+ return printed;
+ }
+
+ public boolean getTitlePrinted() {
+ return mTitlePrinted;
+ }
+
+ public void setTitlePrinted(boolean enabled) {
+ mTitlePrinted = enabled;
+ }
+
+ public SharedUserSetting getSharedUser() {
+ return mSharedUser;
+ }
+
+ public void setSharedUser(SharedUserSetting user) {
+ mSharedUser = user;
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index e1e5b35..37b8ebb 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -49,6 +49,8 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
+import com.android.server.pm.permission.BasePermission;
+
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 49d3c8b..3574466 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -565,7 +565,7 @@
}
public void dumpLPr(PrintWriter pw, String packageName,
- PackageManagerService.DumpState dumpState) {
+ DumpState dumpState) {
boolean printedHeader = false;
for (ArrayMap.Entry<String, PackageSetting> e : mPackages.entrySet()) {
String keySetPackage = e.getKey();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ed8dd8b..815106e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -289,6 +289,7 @@
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
+import com.android.server.pm.permission.BasePermission;
import com.android.server.storage.DeviceStorageMonitorInternal;
import dalvik.system.CloseGuard;
@@ -385,7 +386,7 @@
public class PackageManagerService extends IPackageManager.Stub
implements PackageSender {
static final String TAG = "PackageManager";
- static final boolean DEBUG_SETTINGS = false;
+ public static final boolean DEBUG_SETTINGS = false;
static final boolean DEBUG_PREFERRED = false;
static final boolean DEBUG_UPGRADE = false;
static final boolean DEBUG_DOMAIN_VERIFICATION = false;
@@ -396,7 +397,7 @@
private static final boolean DEBUG_SHOW_INFO = false;
private static final boolean DEBUG_PACKAGE_INFO = false;
private static final boolean DEBUG_INTENT_MATCHING = false;
- private static final boolean DEBUG_PACKAGE_SCANNING = false;
+ public static final boolean DEBUG_PACKAGE_SCANNING = false;
private static final boolean DEBUG_VERIFY = false;
private static final boolean DEBUG_FILTERS = false;
private static final boolean DEBUG_PERMISSIONS = false;
@@ -4272,18 +4273,6 @@
return null;
}
- static PermissionInfo generatePermissionInfo(BasePermission bp, int flags) {
- if (bp.perm != null) {
- return PackageParser.generatePermissionInfo(bp.perm, flags);
- }
- PermissionInfo pi = new PermissionInfo();
- pi.name = bp.name;
- pi.packageName = bp.sourcePackage;
- pi.nonLocalizedLabel = bp.name;
- pi.protectionLevel = bp.protectionLevel;
- return pi;
- }
-
@Override
public PermissionInfo getPermissionInfo(String name, String packageName, int flags) {
final int callingUid = Binder.getCallingUid();
@@ -4292,24 +4281,13 @@
}
// reader
synchronized (mPackages) {
- final BasePermission p = mSettings.mPermissions.get(name);
- if (p == null) {
+ final BasePermission bp = mSettings.mPermissions.get(name);
+ if (bp == null) {
return null;
}
- // If the caller is an app that targets pre 26 SDK drop protection flags.
- PermissionInfo permissionInfo = generatePermissionInfo(p, flags);
- if (permissionInfo != null) {
- final int protectionLevel = adjustPermissionProtectionFlagsLPr(
- permissionInfo.protectionLevel, packageName, callingUid);
- if (permissionInfo.protectionLevel != protectionLevel) {
- // If we return different protection level, don't use the cached info
- if (p.perm != null && p.perm.info == permissionInfo) {
- permissionInfo = new PermissionInfo(permissionInfo);
- }
- permissionInfo.protectionLevel = protectionLevel;
- }
- }
- return permissionInfo;
+ final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLPr(
+ bp.getProtectionLevel(), packageName, callingUid);
+ return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
}
}
@@ -4356,28 +4334,23 @@
}
@Override
- public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String group,
+ public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
int flags) {
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
// reader
synchronized (mPackages) {
- if (group != null && !mPermissionGroups.containsKey(group)) {
+ if (groupName != null && !mPermissionGroups.containsKey(groupName)) {
// This is thrown as NameNotFoundException
return null;
}
ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
- for (BasePermission p : mSettings.mPermissions.values()) {
- if (group == null) {
- if (p.perm == null || p.perm.info.group == null) {
- out.add(generatePermissionInfo(p, flags));
- }
- } else {
- if (p.perm != null && group.equals(p.perm.info.group)) {
- out.add(PackageParser.generatePermissionInfo(p.perm, flags));
- }
+ for (BasePermission bp : mSettings.mPermissions.values()) {
+ final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
+ if (pi != null) {
+ out.add(pi);
}
}
return new ParceledListSlice<>(out);
@@ -5454,75 +5427,10 @@
}
}
- private BasePermission findPermissionTreeLP(String permName) {
- for(BasePermission bp : mSettings.mPermissionTrees.values()) {
- if (permName.startsWith(bp.name) &&
- permName.length() > bp.name.length() &&
- permName.charAt(bp.name.length()) == '.') {
- return bp;
- }
- }
- return null;
- }
-
- private BasePermission checkPermissionTreeLP(String permName) {
- if (permName != null) {
- BasePermission bp = findPermissionTreeLP(permName);
- if (bp != null) {
- if (bp.uid == UserHandle.getAppId(Binder.getCallingUid())) {
- return bp;
- }
- throw new SecurityException("Calling uid "
- + Binder.getCallingUid()
- + " is not allowed to add to permission tree "
- + bp.name + " owned by uid " + bp.uid);
- }
- }
- throw new SecurityException("No permission tree found for " + permName);
- }
-
- static boolean compareStrings(CharSequence s1, CharSequence s2) {
- if (s1 == null) {
- return s2 == null;
- }
- if (s2 == null) {
- return false;
- }
- if (s1.getClass() != s2.getClass()) {
- return false;
- }
- return s1.equals(s2);
- }
-
- static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
- if (pi1.icon != pi2.icon) return false;
- if (pi1.logo != pi2.logo) return false;
- if (pi1.protectionLevel != pi2.protectionLevel) return false;
- if (!compareStrings(pi1.name, pi2.name)) return false;
- if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
- // We'll take care of setting this one.
- if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
- // These are not currently stored in settings.
- //if (!compareStrings(pi1.group, pi2.group)) return false;
- //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
- //if (pi1.labelRes != pi2.labelRes) return false;
- //if (pi1.descriptionRes != pi2.descriptionRes) return false;
- return true;
- }
-
- int permissionInfoFootprint(PermissionInfo info) {
- int size = info.name.length();
- if (info.nonLocalizedLabel != null) size += info.nonLocalizedLabel.length();
- if (info.nonLocalizedDescription != null) size += info.nonLocalizedDescription.length();
- return size;
- }
-
int calculateCurrentPermissionFootprintLocked(BasePermission tree) {
int size = 0;
for (BasePermission perm : mSettings.mPermissions.values()) {
- if (perm.uid == tree.uid) {
- size += perm.name.length() + permissionInfoFootprint(perm.perm.info);
- }
+ size += tree.calculateFootprint(perm);
}
return size;
}
@@ -5530,9 +5438,9 @@
void enforcePermissionCapLocked(PermissionInfo info, BasePermission 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.uid != Process.SYSTEM_UID) {
+ if (tree.getUid() != Process.SYSTEM_UID) {
final int curTreeSize = calculateCurrentPermissionFootprintLocked(tree);
- if (curTreeSize + permissionInfoFootprint(info) > MAX_PERMISSION_TREE_FOOTPRINT) {
+ if (curTreeSize + info.calculateFootprint() > MAX_PERMISSION_TREE_FOOTPRINT) {
throw new SecurityException("Permission tree size cap exceeded");
}
}
@@ -5545,33 +5453,21 @@
if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
throw new SecurityException("Label must be specified in permission");
}
- BasePermission tree = checkPermissionTreeLP(info.name);
+ BasePermission tree = BasePermission.enforcePermissionTreeLP(
+ mSettings.mPermissionTrees, info.name, Binder.getCallingUid());
BasePermission bp = mSettings.mPermissions.get(info.name);
boolean added = bp == null;
- boolean changed = true;
int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
if (added) {
enforcePermissionCapLocked(info, tree);
- bp = new BasePermission(info.name, tree.sourcePackage,
+ bp = new BasePermission(info.name, tree.getSourcePackageName(),
BasePermission.TYPE_DYNAMIC);
- } else if (bp.type != BasePermission.TYPE_DYNAMIC) {
+ } else if (bp.isDynamic()) {
throw new SecurityException(
"Not allowed to modify non-dynamic permission "
+ info.name);
- } else {
- if (bp.protectionLevel == fixedLevel
- && bp.perm.owner.equals(tree.perm.owner)
- && bp.uid == tree.uid
- && comparePermissionInfos(bp.perm.info, info)) {
- changed = false;
- }
}
- bp.protectionLevel = fixedLevel;
- info = new PermissionInfo(info);
- info.protectionLevel = fixedLevel;
- bp.perm = new PackageParser.Permission(tree.perm.owner, info);
- bp.perm.info.packageName = tree.perm.info.packageName;
- bp.uid = tree.uid;
+ final boolean changed = bp.addToTree(fixedLevel, info, tree);
if (added) {
mSettings.mPermissions.put(info.name, bp);
}
@@ -5605,10 +5501,11 @@
throw new SecurityException("Instant applications don't have access to this method");
}
synchronized (mPackages) {
- checkPermissionTreeLP(name);
+ BasePermission.enforcePermissionTreeLP(
+ mSettings.mPermissionTrees, name, Binder.getCallingUid());
BasePermission bp = mSettings.mPermissions.get(name);
if (bp != null) {
- if (bp.type != BasePermission.TYPE_DYNAMIC) {
+ if (bp.isDynamic()) {
throw new SecurityException(
"Not allowed to modify non-dynamic permission "
+ name);
@@ -5619,19 +5516,6 @@
}
}
- private static void enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(
- PackageParser.Package pkg, BasePermission bp) {
- int index = pkg.requestedPermissions.indexOf(bp.name);
- if (index == -1) {
- throw new SecurityException("Package " + pkg.packageName
- + " has not requested permission " + bp.name);
- }
- if (!bp.isRuntime() && !bp.isDevelopment()) {
- throw new SecurityException("Permission " + bp.name
- + " is not a changeable permission type");
- }
- }
-
@Override
public void grantRuntimePermission(String packageName, String name, final int userId) {
grantRuntimePermission(packageName, name, userId, false /* Only if not fixed by policy */);
@@ -5671,7 +5555,7 @@
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -5800,7 +5684,7 @@
throw new IllegalArgumentException("Unknown permission: " + name);
}
- enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -9106,7 +8990,7 @@
return fname;
}
- static void reportSettingsProblem(int priority, String msg) {
+ public static void reportSettingsProblem(int priority, String msg) {
logCriticalInfo(priority, msg);
}
@@ -11860,84 +11744,12 @@
}
}
- ArrayMap<String, BasePermission> permissionMap =
+ final ArrayMap<String, BasePermission> permissionMap =
p.tree ? mSettings.mPermissionTrees
: mSettings.mPermissions;
- BasePermission bp = permissionMap.get(p.info.name);
-
- // Allow system apps to redefine non-system permissions
- if (bp != null && !Objects.equals(bp.sourcePackage, p.info.packageName)) {
- final boolean currentOwnerIsSystem = (bp.perm != null
- && isSystemApp(bp.perm.owner));
- if (isSystemApp(p.owner)) {
- if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
- // It's a built-in permission and no owner, take ownership now
- bp.packageSetting = pkgSetting;
- bp.perm = p;
- bp.uid = pkg.applicationInfo.uid;
- bp.sourcePackage = p.info.packageName;
- p.info.flags |= PermissionInfo.FLAG_INSTALLED;
- } else if (!currentOwnerIsSystem) {
- String msg = "New decl " + p.owner + " of permission "
- + p.info.name + " is system; overriding " + bp.sourcePackage;
- reportSettingsProblem(Log.WARN, msg);
- bp = null;
- }
- }
- }
-
- if (bp == null) {
- bp = new BasePermission(p.info.name, p.info.packageName,
- BasePermission.TYPE_NORMAL);
- permissionMap.put(p.info.name, bp);
- }
-
- if (bp.perm == null) {
- if (bp.sourcePackage == null
- || bp.sourcePackage.equals(p.info.packageName)) {
- BasePermission tree = findPermissionTreeLP(p.info.name);
- if (tree == null
- || tree.sourcePackage.equals(p.info.packageName)) {
- bp.packageSetting = pkgSetting;
- bp.perm = p;
- bp.uid = pkg.applicationInfo.uid;
- bp.sourcePackage = p.info.packageName;
- p.info.flags |= PermissionInfo.FLAG_INSTALLED;
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(p.info.name);
- }
- } else {
- Slog.w(TAG, "Permission " + p.info.name + " from package "
- + p.info.packageName + " ignored: base tree "
- + tree.name + " is from package "
- + tree.sourcePackage);
- }
- } else {
- Slog.w(TAG, "Permission " + p.info.name + " from package "
- + p.info.packageName + " ignored: original from "
- + bp.sourcePackage);
- }
- } else if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append("DUP:");
- r.append(p.info.name);
- }
- if (bp.perm == p) {
- bp.protectionLevel = p.info.protectionLevel;
- }
- }
-
- if (r != null) {
- if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permissions: " + r);
+ final BasePermission bp = BasePermission.createOrUpdate(
+ permissionMap.get(p.info.name), p, pkg, mSettings.mPermissionTrees, chatty);
+ permissionMap.put(p.info.name, bp);
}
N = pkg.instrumentation.size();
@@ -12671,8 +12483,8 @@
if (bp == null) {
bp = mSettings.mPermissionTrees.get(p.info.name);
}
- if (bp != null && bp.perm == p) {
- bp.perm = null;
+ if (bp != null && bp.isPermission(p)) {
+ bp.setPermission(null);
if (DEBUG_REMOVE && chatty) {
if (r == null) {
r = new StringBuilder(256);
@@ -12698,7 +12510,7 @@
for (i=0; i<N; i++) {
String perm = pkg.requestedPermissions.get(i);
BasePermission bp = mSettings.mPermissions.get(perm);
- if (bp != null && (bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
+ if (bp != null && bp.isAppOp()) {
ArraySet<String> appOpPkgs = mAppOpPermissionPackages.get(perm);
if (appOpPkgs != null) {
appOpPkgs.remove(pkg.packageName);
@@ -12803,23 +12615,32 @@
private void updatePermissionsLPw(String changingPkg,
PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) {
+ // TODO: Most of the methods exposing BasePermission internals [source package name,
+ // etc..] shouldn't be needed. Instead, when we've parsed a permission that doesn't
+ // have package settings, we should make note of it elsewhere [map between
+ // source package name and BasePermission] and cycle through that here. Then we
+ // define a single method on BasePermission that takes a PackageSetting, changing
+ // package name and a package.
+ // NOTE: With this approach, we also don't need to tree trees differently than
+ // normal permissions. Today, we need two separate loops because these BasePermission
+ // objects are stored separately.
// Make sure there are no dangling permission trees.
Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
while (it.hasNext()) {
final BasePermission bp = it.next();
- if (bp.packageSetting == null) {
+ if (bp.getSourcePackageSetting() == null) {
// We may not yet have parsed the package, so just see if
// we still know about its settings.
- bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
+ bp.setSourcePackageSetting(mSettings.mPackages.get(bp.getSourcePackageName()));
}
- if (bp.packageSetting == null) {
- Slog.w(TAG, "Removing dangling permission tree: " + bp.name
- + " from package " + bp.sourcePackage);
+ if (bp.getSourcePackageSetting() == null) {
+ Slog.w(TAG, "Removing dangling permission tree: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
it.remove();
- } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
- if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
- Slog.i(TAG, "Removing old permission tree: " + bp.name
- + " from package " + bp.sourcePackage);
+ } else if (changingPkg != null && changingPkg.equals(bp.getSourcePackageName())) {
+ if (pkgInfo == null || !hasPermission(pkgInfo, bp.getName())) {
+ Slog.i(TAG, "Removing old permission tree: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
flags |= UPDATE_PERMISSIONS_ALL;
it.remove();
}
@@ -12831,35 +12652,22 @@
it = mSettings.mPermissions.values().iterator();
while (it.hasNext()) {
final BasePermission bp = it.next();
- if (bp.type == BasePermission.TYPE_DYNAMIC) {
- if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
- + bp.name + " pkg=" + bp.sourcePackage
- + " info=" + bp.pendingInfo);
- if (bp.packageSetting == null && bp.pendingInfo != null) {
- final BasePermission tree = findPermissionTreeLP(bp.name);
- if (tree != null && tree.perm != null) {
- bp.packageSetting = tree.packageSetting;
- bp.perm = new PackageParser.Permission(tree.perm.owner,
- new PermissionInfo(bp.pendingInfo));
- bp.perm.info.packageName = tree.perm.info.packageName;
- bp.perm.info.name = bp.name;
- bp.uid = tree.uid;
- }
- }
+ if (bp.isDynamic()) {
+ bp.updateDynamicPermission(mSettings.mPermissionTrees);
}
- if (bp.packageSetting == null) {
+ if (bp.getSourcePackageSetting() == null) {
// We may not yet have parsed the package, so just see if
// we still know about its settings.
- bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
+ bp.setSourcePackageSetting(mSettings.mPackages.get(bp.getSourcePackageName()));
}
- if (bp.packageSetting == null) {
- Slog.w(TAG, "Removing dangling permission: " + bp.name
- + " from package " + bp.sourcePackage);
+ if (bp.getSourcePackageSetting() == null) {
+ Slog.w(TAG, "Removing dangling permission: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
it.remove();
- } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
- if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
- Slog.i(TAG, "Removing old permission: " + bp.name
- + " from package " + bp.sourcePackage);
+ } else if (changingPkg != null && changingPkg.equals(bp.getSourcePackageName())) {
+ if (pkgInfo == null || !hasPermission(pkgInfo, bp.getName())) {
+ Slog.i(TAG, "Removing old permission: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
flags |= UPDATE_PERMISSIONS_ALL;
it.remove();
}
@@ -12951,7 +12759,7 @@
Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
}
- if (bp == null || bp.packageSetting == null) {
+ if (bp == null || bp.getSourcePackageSetting() == null) {
if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
if (DEBUG_PERMISSIONS) {
Slog.i(TAG, "Unknown permission " + name
@@ -12965,7 +12773,7 @@
// Limit ephemeral apps to ephemeral allowed permissions.
if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
if (DEBUG_PERMISSIONS) {
- Log.i(TAG, "Denying non-ephemeral permission " + bp.name + " for package "
+ Log.i(TAG, "Denying non-ephemeral permission " + bp.getName() + " for package "
+ pkg.packageName);
}
continue;
@@ -12973,64 +12781,57 @@
if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
if (DEBUG_PERMISSIONS) {
- Log.i(TAG, "Denying runtime-only permission " + bp.name + " for package "
+ Log.i(TAG, "Denying runtime-only permission " + bp.getName() + " for package "
+ pkg.packageName);
}
continue;
}
- final String perm = bp.name;
+ final String perm = bp.getName();
boolean allowedSig = false;
int grant = GRANT_DENIED;
// Keep track of app op permissions.
- if ((bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
- ArraySet<String> pkgs = mAppOpPermissionPackages.get(bp.name);
+ if (bp.isAppOp()) {
+ ArraySet<String> pkgs = mAppOpPermissionPackages.get(perm);
if (pkgs == null) {
pkgs = new ArraySet<>();
- mAppOpPermissionPackages.put(bp.name, pkgs);
+ mAppOpPermissionPackages.put(perm, pkgs);
}
pkgs.add(pkg.packageName);
}
- final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
- switch (level) {
- case PermissionInfo.PROTECTION_NORMAL: {
- // For all apps normal permissions are install time ones.
+ if (bp.isNormal()) {
+ // For all apps normal permissions are install time ones.
+ grant = GRANT_INSTALL;
+ } else if (bp.isRuntime()) {
+ // If a permission review is required for legacy apps we represent
+ // their permissions as always granted runtime ones since we need
+ // to keep the review required permission flag per user while an
+ // install permission's state is shared across all users.
+ if (!appSupportsRuntimePermissions && !mPermissionReviewRequired) {
+ // For legacy apps dangerous permissions are install time ones.
grant = GRANT_INSTALL;
- } break;
-
- case PermissionInfo.PROTECTION_DANGEROUS: {
- // If a permission review is required for legacy apps we represent
- // their permissions as always granted runtime ones since we need
- // to keep the review required permission flag per user while an
- // install permission's state is shared across all users.
- if (!appSupportsRuntimePermissions && !mPermissionReviewRequired) {
- // For legacy apps dangerous permissions are install time ones.
- grant = GRANT_INSTALL;
- } else if (origPermissions.hasInstallPermission(bp.name)) {
- // For legacy apps that became modern, install becomes runtime.
- grant = GRANT_UPGRADE;
- } else if (mPromoteSystemApps
- && isSystemApp(ps)
- && mExistingSystemPackages.contains(ps.name)) {
- // For legacy system apps, install becomes runtime.
- // We cannot check hasInstallPermission() for system apps since those
- // permissions were granted implicitly and not persisted pre-M.
- grant = GRANT_UPGRADE;
- } else {
- // For modern apps keep runtime permissions unchanged.
- grant = GRANT_RUNTIME;
- }
- } break;
-
- case PermissionInfo.PROTECTION_SIGNATURE: {
- // For all apps signature permissions are install time ones.
- allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
- if (allowedSig) {
- grant = GRANT_INSTALL;
- }
- } break;
+ } else if (origPermissions.hasInstallPermission(bp.getName())) {
+ // For legacy apps that became modern, install becomes runtime.
+ grant = GRANT_UPGRADE;
+ } else if (mPromoteSystemApps
+ && isSystemApp(ps)
+ && mExistingSystemPackages.contains(ps.name)) {
+ // For legacy system apps, install becomes runtime.
+ // We cannot check hasInstallPermission() for system apps since those
+ // permissions were granted implicitly and not persisted pre-M.
+ grant = GRANT_UPGRADE;
+ } else {
+ // For modern apps keep runtime permissions unchanged.
+ grant = GRANT_RUNTIME;
+ }
+ } else if (bp.isSignature()) {
+ // For all apps signature permissions are install time ones.
+ allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
+ if (allowedSig) {
+ grant = GRANT_INSTALL;
+ }
}
if (DEBUG_PERMISSIONS) {
@@ -13059,7 +12860,7 @@
// for legacy apps
for (int userId : UserManagerService.getInstance().getUserIds()) {
if (origPermissions.getRuntimePermissionState(
- bp.name, userId) != null) {
+ perm, userId) != null) {
// Revoke the runtime permission and clear the flags.
origPermissions.revokeRuntimePermission(bp, userId);
origPermissions.updatePermissionFlags(bp, userId,
@@ -13080,10 +12881,10 @@
// Grant previously granted runtime permissions.
for (int userId : UserManagerService.getInstance().getUserIds()) {
PermissionState permissionState = origPermissions
- .getRuntimePermissionState(bp.name, userId);
+ .getRuntimePermissionState(perm, userId);
int flags = permissionState != null
? permissionState.getFlags() : 0;
- if (origPermissions.hasRuntimePermission(bp.name, userId)) {
+ if (origPermissions.hasRuntimePermission(perm, userId)) {
// Don't propagate the permission in a permission review mode if
// the former was revoked, i.e. marked to not propagate on upgrade.
// Note that in a permission review mode install permissions are
@@ -13126,7 +12927,7 @@
// permissions as these are the only ones the platform knows
// how to disable the API to simulate revocation as legacy
// apps don't expect to run with revoked permissions.
- if (PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage)) {
+ if (PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName())) {
if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
// We changed the flags, hence have to write.
@@ -13149,7 +12950,7 @@
case GRANT_UPGRADE: {
// Grant runtime permissions for a previously held install permission.
PermissionState permissionState = origPermissions
- .getInstallPermissionState(bp.name);
+ .getInstallPermissionState(perm);
final int flags = permissionState != null ? permissionState.getFlags() : 0;
if (origPermissions.revokeInstallPermission(bp)
@@ -13197,10 +12998,10 @@
changedInstallPermission = true;
Slog.i(TAG, "Un-granting permission " + perm
+ " from package " + pkg.packageName
- + " (protectionLevel=" + bp.protectionLevel
+ + " (protectionLevel=" + bp.getProtectionLevel()
+ " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ ")");
- } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {
+ } else if (bp.isAppOp()) {
// Don't print warning for app op permissions, since it is fine for them
// not to be granted, there is a UI for the user to decide.
if (DEBUG_PERMISSIONS
@@ -13208,7 +13009,7 @@
|| packageOfInterest.equals(pkg.packageName))) {
Slog.i(TAG, "Not granting permission " + perm
+ " to package " + pkg.packageName
- + " (protectionLevel=" + bp.protectionLevel
+ + " (protectionLevel=" + bp.getProtectionLevel()
+ " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ ")");
}
@@ -13268,13 +13069,11 @@
private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
BasePermission bp, PermissionsState origPermissions) {
- boolean oemPermission = (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_OEM) != 0;
- boolean privilegedPermission = (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
+ boolean oemPermission = bp.isOEM();
+ boolean privilegedPermission = bp.isPrivileged();
boolean privappPermissionsDisable =
RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE;
- boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage);
+ boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName());
boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName);
if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivilegedApp()
&& !platformPackage && platformPermission) {
@@ -13303,7 +13102,7 @@
}
}
boolean allowed = (compareSignatures(
- bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
+ bp.getSourcePackageSetting().signatures.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
|| (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
@@ -13380,39 +13179,37 @@
}
}
if (!allowed) {
- if (!allowed && (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_PRE23) != 0
+ if (!allowed
+ && bp.isPre23()
&& pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
// If this was a previously normal/dangerous permission that got moved
// to a system permission as part of the runtime permission redesign, then
// we still want to blindly grant it to old apps.
allowed = true;
}
- if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0
+ if (!allowed && bp.isInstaller()
&& pkg.packageName.equals(mRequiredInstallerPackage)) {
// If this permission is to be granted to the system installer and
// this app is an installer, then it gets the permission.
allowed = true;
}
- if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0
+ if (!allowed && bp.isVerifier()
&& pkg.packageName.equals(mRequiredVerifierPackage)) {
// If this permission is to be granted to the system verifier and
// this app is a verifier, then it gets the permission.
allowed = true;
}
- if (!allowed && (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0
+ if (!allowed && bp.isPreInstalled()
&& isSystemApp(pkg)) {
// Any pre-installed system app is allowed to get this permission.
allowed = true;
}
- if (!allowed && (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
+ if (!allowed && bp.isDevelopment()) {
// For development permissions, a development permission
// is granted only if it was already granted.
allowed = origPermissions.hasInstallPermission(perm);
}
- if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0
+ if (!allowed && bp.isSetup()
&& pkg.packageName.equals(mSetupWizardPackage)) {
// If this permission is to be granted to the system setup wizard and
// this app is a setup wizard, then it gets the permission.
@@ -17621,9 +17418,9 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- private boolean shouldCheckUpgradeKeySetLP(PackageSetting oldPs, int scanFlags) {
+ private boolean shouldCheckUpgradeKeySetLP(PackageSettingBase oldPs, int scanFlags) {
// Can't rotate keys during boot or if sharedUser.
- if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.sharedUser != null
+ if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
|| !oldPs.keySetData.isUsingUpgradeKeySets()) {
return false;
}
@@ -17643,7 +17440,7 @@
return true;
}
- private boolean checkUpgradeKeySetLP(PackageSetting oldPS, PackageParser.Package newPkg) {
+ private boolean checkUpgradeKeySetLP(PackageSettingBase oldPS, PackageParser.Package newPkg) {
// Upgrade keysets are being used. Determine if new package has a superset of the
// required keys.
long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
@@ -18697,25 +18494,26 @@
// also includes the "updating the same package" case, of course.
// "updating same package" could also involve key-rotation.
final boolean sigsOk;
- if (bp.sourcePackage.equals(pkg.packageName)
- && (bp.packageSetting instanceof PackageSetting)
- && (shouldCheckUpgradeKeySetLP((PackageSetting) bp.packageSetting,
+ final String sourcePackageName = bp.getSourcePackageName();
+ final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
+ if (sourcePackageName.equals(pkg.packageName)
+ && (shouldCheckUpgradeKeySetLP(sourcePackageSetting,
scanFlags))) {
- sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);
+ sigsOk = checkUpgradeKeySetLP(sourcePackageSetting, pkg);
} else {
- sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,
+ sigsOk = compareSignatures(sourcePackageSetting.signatures.mSignatures,
pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
}
if (!sigsOk) {
// If the owning package is the system itself, we log but allow
// install to proceed; we fail the install on all other permission
// redefinitions.
- if (!bp.sourcePackage.equals("android")) {
+ if (!sourcePackageName.equals("android")) {
res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
+ pkg.packageName + " attempting to redeclare permission "
- + perm.info.name + " already owned by " + bp.sourcePackage);
+ + perm.info.name + " already owned by " + sourcePackageName);
res.origPermission = perm.info.name;
- res.origPackage = bp.sourcePackage;
+ res.origPackage = sourcePackageName;
return;
} else {
Slog.w(TAG, "Package " + pkg.packageName
@@ -18734,7 +18532,7 @@
Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
+ "non-runtime permission " + perm.info.name
+ " to runtime; keeping old protection level");
- perm.info.protectionLevel = bp.protectionLevel;
+ perm.info.protectionLevel = bp.getProtectionLevel();
}
}
}
@@ -20573,9 +20371,8 @@
final int permissionCount = ps.pkg.requestedPermissions.size();
for (int i = 0; i < permissionCount; i++) {
- String permission = ps.pkg.requestedPermissions.get(i);
-
- BasePermission bp = mSettings.mPermissions.get(permission);
+ final String permissionName = ps.pkg.requestedPermissions.get(i);
+ final BasePermission bp = mSettings.mPermissions.get(permissionName);
if (bp == null) {
continue;
}
@@ -20587,7 +20384,7 @@
for (int j = 0; j < packageCount; j++) {
PackageSetting pkg = ps.sharedUser.packages.valueAt(j);
if (pkg.pkg != null && !pkg.pkg.packageName.equals(ps.pkg.packageName)
- && pkg.pkg.requestedPermissions.contains(permission)) {
+ && pkg.pkg.requestedPermissions.contains(permissionName)) {
used = true;
break;
}
@@ -20597,13 +20394,13 @@
}
}
- PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = ps.getPermissionsState();
- final int oldFlags = permissionsState.getPermissionFlags(bp.name, userId);
+ final int oldFlags = permissionsState.getPermissionFlags(permissionName, userId);
// Always clear the user settable flags.
- final boolean hasInstallState = permissionsState.getInstallPermissionState(
- bp.name) != null;
+ final boolean hasInstallState =
+ permissionsState.getInstallPermissionState(permissionName) != null;
// If permission review is enabled and this is a legacy app, mark the
// permission as requiring a review as this is the initial state.
int flags = 0;
@@ -22459,85 +22256,6 @@
return buf.toString();
}
- static class DumpState {
- public static final int DUMP_LIBS = 1 << 0;
- public static final int DUMP_FEATURES = 1 << 1;
- public static final int DUMP_ACTIVITY_RESOLVERS = 1 << 2;
- public static final int DUMP_SERVICE_RESOLVERS = 1 << 3;
- public static final int DUMP_RECEIVER_RESOLVERS = 1 << 4;
- public static final int DUMP_CONTENT_RESOLVERS = 1 << 5;
- public static final int DUMP_PERMISSIONS = 1 << 6;
- public static final int DUMP_PACKAGES = 1 << 7;
- public static final int DUMP_SHARED_USERS = 1 << 8;
- public static final int DUMP_MESSAGES = 1 << 9;
- public static final int DUMP_PROVIDERS = 1 << 10;
- public static final int DUMP_VERIFIERS = 1 << 11;
- public static final int DUMP_PREFERRED = 1 << 12;
- public static final int DUMP_PREFERRED_XML = 1 << 13;
- public static final int DUMP_KEYSETS = 1 << 14;
- public static final int DUMP_VERSION = 1 << 15;
- public static final int DUMP_INSTALLS = 1 << 16;
- public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 17;
- public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
- public static final int DUMP_FROZEN = 1 << 19;
- public static final int DUMP_DEXOPT = 1 << 20;
- public static final int DUMP_COMPILER_STATS = 1 << 21;
- public static final int DUMP_CHANGES = 1 << 22;
- public static final int DUMP_VOLUMES = 1 << 23;
-
- public static final int OPTION_SHOW_FILTERS = 1 << 0;
-
- private int mTypes;
-
- private int mOptions;
-
- private boolean mTitlePrinted;
-
- private SharedUserSetting mSharedUser;
-
- public boolean isDumping(int type) {
- if (mTypes == 0 && type != DUMP_PREFERRED_XML) {
- return true;
- }
-
- return (mTypes & type) != 0;
- }
-
- public void setDump(int type) {
- mTypes |= type;
- }
-
- public boolean isOptionEnabled(int option) {
- return (mOptions & option) != 0;
- }
-
- public void setOptionEnabled(int option) {
- mOptions |= option;
- }
-
- public boolean onTitlePrinted() {
- final boolean printed = mTitlePrinted;
- mTitlePrinted = true;
- return printed;
- }
-
- public boolean getTitlePrinted() {
- return mTitlePrinted;
- }
-
- public void setTitlePrinted(boolean enabled) {
- mTitlePrinted = enabled;
- }
-
- public SharedUserSetting getSharedUser() {
- return mSharedUser;
- }
-
- public void setSharedUser(SharedUserSetting user) {
- mSharedUser = user;
- }
- }
-
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
@@ -24867,7 +24585,8 @@
synchronized (mPackages) {
if (mSettings.mReadExternalStorageEnforced == null
|| mSettings.mReadExternalStorageEnforced != enforced) {
- mSettings.mReadExternalStorageEnforced = enforced;
+ mSettings.mReadExternalStorageEnforced =
+ enforced ? Boolean.TRUE : Boolean.FALSE;
mSettings.writeLPr();
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 52bf641..88fe3c1 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -103,6 +103,7 @@
sharedUserId = orig.sharedUserId;
}
+ @Override
public PermissionsState getPermissionsState() {
return (sharedUser != null)
? sharedUser.getPermissionsState()
@@ -125,6 +126,7 @@
return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
+ @Override
public boolean isSharedUser() {
return sharedUser != null;
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index d3ca1fd..0d4878f 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -24,14 +24,12 @@
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageUserState;
-import android.os.storage.VolumeInfo;
import android.service.pm.PackageProto;
import android.util.ArraySet;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
-import com.google.android.collect.Lists;
import java.io.File;
import java.util.ArrayList;
@@ -42,7 +40,7 @@
/**
* Settings base class for pending and resolved classes.
*/
-abstract class PackageSettingBase extends SettingBase {
+public abstract class PackageSettingBase extends SettingBase {
private static final int[] EMPTY_INT_ARRAY = new int[0];
@@ -230,6 +228,9 @@
return updateAvailable;
}
+ public boolean isSharedUser() {
+ return false;
+ }
/**
* Makes a shallow copy of the given package settings.
*
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index f4d2ad2..8b42a99 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -24,6 +24,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.permission.BasePermission;
import java.util.ArrayList;
import java.util.Arrays;
@@ -406,7 +407,7 @@
ensurePermissionData(permission);
}
- PermissionData permissionData = mPermissions.get(permission.name);
+ PermissionData permissionData = mPermissions.get(permission.getName());
if (permissionData == null) {
if (!mayChangeFlags) {
return false;
@@ -557,7 +558,7 @@
}
private int grantPermission(BasePermission permission, int userId) {
- if (hasPermission(permission.name, userId)) {
+ if (hasPermission(permission.getName(), userId)) {
return PERMISSION_OPERATION_FAILURE;
}
@@ -581,21 +582,22 @@
}
private int revokePermission(BasePermission permission, int userId) {
- if (!hasPermission(permission.name, userId)) {
+ final String permName = permission.getName();
+ if (!hasPermission(permName, userId)) {
return PERMISSION_OPERATION_FAILURE;
}
final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
- PermissionData permissionData = mPermissions.get(permission.name);
+ PermissionData permissionData = mPermissions.get(permName);
if (!permissionData.revoke(userId)) {
return PERMISSION_OPERATION_FAILURE;
}
if (permissionData.isDefault()) {
- ensureNoPermissionData(permission.name);
+ ensureNoPermissionData(permName);
}
if (hasGids) {
@@ -625,13 +627,14 @@
}
private PermissionData ensurePermissionData(BasePermission permission) {
+ final String permName = permission.getName();
if (mPermissions == null) {
mPermissions = new ArrayMap<>();
}
- PermissionData permissionData = mPermissions.get(permission.name);
+ PermissionData permissionData = mPermissions.get(permName);
if (permissionData == null) {
permissionData = new PermissionData(permission);
- mPermissions.put(permission.name, permissionData);
+ mPermissions.put(permName, permissionData);
}
return permissionData;
}
@@ -692,7 +695,7 @@
PermissionState userState = mUserStates.get(userId);
if (userState == null) {
- userState = new PermissionState(mPerm.name);
+ userState = new PermissionState(mPerm.getName());
mUserStates.put(userId, userState);
}
@@ -760,7 +763,7 @@
}
return userState.mFlags != oldFlags;
} else if (newFlags != 0) {
- userState = new PermissionState(mPerm.name);
+ userState = new PermissionState(mPerm.getName());
userState.mFlags = newFlags;
mUserStates.put(userId, userState);
return true;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 51d3e10..06cf79a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -16,7 +16,6 @@
package com.android.server.pm;
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
@@ -64,7 +63,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
-import android.os.storage.VolumeInfo;
import android.service.pm.PackageServiceDumpProto;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -87,10 +85,9 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
-import com.android.server.backup.PreferredActivityBackupHelper;
import com.android.server.pm.Installer.InstallerException;
-import com.android.server.pm.PackageManagerService.DumpState;
import com.android.server.pm.PermissionsState.PermissionState;
+import com.android.server.pm.permission.BasePermission;
import libcore.io.IoUtils;
@@ -127,7 +124,7 @@
/**
* Holds information about dynamic settings.
*/
-final class Settings {
+public final class Settings {
private static final String TAG = "PackageSettings";
/**
@@ -176,7 +173,7 @@
private static final String TAG_READ_EXTERNAL_STORAGE = "read-external-storage";
private static final String ATTR_ENFORCEMENT = "enforcement";
- private static final String TAG_ITEM = "item";
+ public static final String TAG_ITEM = "item";
private static final String TAG_DISABLED_COMPONENTS = "disabled-components";
private static final String TAG_ENABLED_COMPONENTS = "enabled-components";
private static final String TAG_PACKAGE_RESTRICTIONS = "package-restrictions";
@@ -201,7 +198,8 @@
private static final String TAG_DEFAULT_DIALER = "default-dialer";
private static final String TAG_VERSION = "version";
- private static final String ATTR_NAME = "name";
+ public static final String ATTR_NAME = "name";
+ public static final String ATTR_PACKAGE = "package";
private static final String ATTR_USER = "user";
private static final String ATTR_CODE = "code";
private static final String ATTR_GRANTED = "granted";
@@ -233,7 +231,6 @@
private static final String ATTR_VOLUME_UUID = "volumeUuid";
private static final String ATTR_SDK_VERSION = "sdkVersion";
private static final String ATTR_DATABASE_VERSION = "databaseVersion";
- private static final String ATTR_DONE = "done";
// Bookkeeping for restored permission grants
private static final String TAG_RESTORED_RUNTIME_PERMISSIONS = "restored-perms";
@@ -665,26 +662,13 @@
}
// Transfer ownership of permissions from one package to another.
- void transferPermissionsLPw(String origPkg, String newPkg) {
+ void transferPermissionsLPw(String origPackageName, String newPackageName) {
// Transfer ownership of permissions to the new package.
for (int i=0; i<2; i++) {
ArrayMap<String, BasePermission> permissions =
i == 0 ? mPermissionTrees : mPermissions;
for (BasePermission bp : permissions.values()) {
- if (origPkg.equals(bp.sourcePackage)) {
- if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG,
- "Moving permission " + bp.name
- + " from pkg " + bp.sourcePackage
- + " to " + newPkg);
- bp.sourcePackage = newPkg;
- bp.packageSetting = null;
- bp.perm = null;
- if (bp.pendingInfo != null) {
- bp.pendingInfo.packageName = newPkg;
- }
- bp.uid = 0;
- bp.setGids(null, false);
- }
+ bp.transfer(origPackageName, newPackageName);
}
}
}
@@ -2022,8 +2006,7 @@
// Specifically for backup/restore
public void processRestoredPermissionGrantLPr(String pkgName, String permission,
- boolean isGranted, int restoredFlagSet, int userId)
- throws IOException, XmlPullParserException {
+ boolean isGranted, int restoredFlagSet, int userId) {
mRuntimePermissionsPersistence.rememberRestoredUserGrantLPr(
pkgName, permission, isGranted, restoredFlagSet, userId);
}
@@ -2605,9 +2588,6 @@
writeAllRuntimePermissionsLPr();
return;
- } catch(XmlPullParserException e) {
- Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
- + "current changes will be lost at reboot", e);
} catch(java.io.IOException e) {
Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ "current changes will be lost at reboot", e);
@@ -2951,7 +2931,6 @@
void writeUpgradeKeySetsLPr(XmlSerializer serializer,
PackageKeySetData data) throws IOException {
- long properSigning = data.getProperSigningKeySet();
if (data.isUsingUpgradeKeySets()) {
for (long id : data.getUpgradeKeySets()) {
serializer.startTag(null, "upgrade-keyset");
@@ -2971,32 +2950,8 @@
}
}
- void writePermissionLPr(XmlSerializer serializer, BasePermission bp)
- throws XmlPullParserException, java.io.IOException {
- if (bp.sourcePackage != null) {
- serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME, bp.name);
- serializer.attribute(null, "package", bp.sourcePackage);
- if (bp.protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
- serializer.attribute(null, "protection", Integer.toString(bp.protectionLevel));
- }
- if (PackageManagerService.DEBUG_SETTINGS)
- Log.v(PackageManagerService.TAG, "Writing perm: name=" + bp.name + " type="
- + bp.type);
- if (bp.type == BasePermission.TYPE_DYNAMIC) {
- final PermissionInfo pi = bp.perm != null ? bp.perm.info : bp.pendingInfo;
- if (pi != null) {
- serializer.attribute(null, "type", "dynamic");
- if (pi.icon != 0) {
- serializer.attribute(null, "icon", Integer.toString(pi.icon));
- }
- if (pi.nonLocalizedLabel != null) {
- serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
- }
- }
- }
- serializer.endTag(null, TAG_ITEM);
- }
+ void writePermissionLPr(XmlSerializer serializer, BasePermission bp) throws IOException {
+ bp.writeLPr(serializer);
}
ArrayList<PackageSetting> getListOfIncompleteInstallPackagesLPr() {
@@ -3169,7 +3124,8 @@
}
} else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
- mReadExternalStorageEnforced = "1".equals(enforcement);
+ mReadExternalStorageEnforced =
+ "1".equals(enforcement) ? Boolean.TRUE : Boolean.FALSE;
} else if (tagName.equals("keyset-settings")) {
mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs);
} else if (TAG_VERSION.equals(tagName)) {
@@ -3593,22 +3549,6 @@
}
}
- private 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;
- }
-
private void readPermissionsLPw(ArrayMap<String, BasePermission> out, XmlPullParser parser)
throws IOException, XmlPullParserException {
int outerDepth = parser.getDepth();
@@ -3619,38 +3559,7 @@
continue;
}
- final String tagName = parser.getName();
- if (tagName.equals(TAG_ITEM)) {
- final String name = parser.getAttributeValue(null, ATTR_NAME);
- final String sourcePackage = parser.getAttributeValue(null, "package");
- final String ptype = parser.getAttributeValue(null, "type");
- if (name != null && sourcePackage != null) {
- final boolean dynamic = "dynamic".equals(ptype);
- BasePermission bp = out.get(name);
- // If the permission is builtin, do not clobber it.
- if (bp == null || bp.type != BasePermission.TYPE_BUILTIN) {
- bp = new BasePermission(name.intern(), sourcePackage,
- dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL);
- }
- bp.protectionLevel = readInt(parser, null, "protection",
- PermissionInfo.PROTECTION_NORMAL);
- bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
- if (dynamic) {
- PermissionInfo pi = new PermissionInfo();
- pi.packageName = sourcePackage.intern();
- pi.name = name.intern();
- pi.icon = readInt(parser, null, "icon", 0);
- pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
- pi.protectionLevel = bp.protectionLevel;
- bp.pendingInfo = pi;
- }
- out.put(bp.name, bp);
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Error in package manager settings: permissions has" + " no name at "
- + parser.getPositionDescription());
- }
- } else {
+ if (!BasePermission.readLPw(out, parser)) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unknown element reading permissions: " + parser.getName() + " at "
+ parser.getPositionDescription());
@@ -4385,10 +4294,6 @@
return ps;
}
- private String compToString(ArraySet<String> cmp) {
- return cmp != null ? Arrays.toString(cmp.toArray()) : "[]";
- }
-
boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
final PackageSetting ps = mPackages.get(componentInfo.packageName);
if (ps == null) return false;
@@ -5002,43 +4907,9 @@
void dumpPermissionsLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
DumpState dumpState) {
boolean printedSomething = false;
- for (BasePermission p : mPermissions.values()) {
- if (packageName != null && !packageName.equals(p.sourcePackage)) {
- continue;
- }
- if (permissionNames != null && !permissionNames.contains(p.name)) {
- continue;
- }
- if (!printedSomething) {
- if (dumpState.onTitlePrinted())
- pw.println();
- pw.println("Permissions:");
- printedSomething = true;
- }
- pw.print(" Permission ["); pw.print(p.name); pw.print("] (");
- pw.print(Integer.toHexString(System.identityHashCode(p)));
- pw.println("):");
- pw.print(" sourcePackage="); pw.println(p.sourcePackage);
- pw.print(" uid="); pw.print(p.uid);
- pw.print(" gids="); pw.print(Arrays.toString(
- p.computeGids(UserHandle.USER_SYSTEM)));
- pw.print(" type="); pw.print(p.type);
- pw.print(" prot=");
- pw.println(PermissionInfo.protectionToString(p.protectionLevel));
- if (p.perm != null) {
- pw.print(" perm="); pw.println(p.perm);
- if ((p.perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
- || (p.perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
- pw.print(" flags=0x"); pw.println(Integer.toHexString(p.perm.info.flags));
- }
- }
- if (p.packageSetting != null) {
- pw.print(" packageSetting="); pw.println(p.packageSetting);
- }
- if (READ_EXTERNAL_STORAGE.equals(p.name)) {
- pw.print(" enforced=");
- pw.println(mReadExternalStorageEnforced);
- }
+ for (BasePermission bp : mPermissions.values()) {
+ printedSomething = bp.dumpPermissionsLPr(pw, packageName, permissionNames,
+ mReadExternalStorageEnforced == Boolean.TRUE, printedSomething, dumpState);
}
}
@@ -5248,7 +5119,7 @@
private final Handler mHandler = new MyHandler();
- private final Object mLock;
+ private final Object mPersistenceLock;
@GuardedBy("mLock")
private final SparseBooleanArray mWriteScheduled = new SparseBooleanArray();
@@ -5265,8 +5136,8 @@
// The mapping keys are user ids.
private final SparseBooleanArray mDefaultPermissionsGranted = new SparseBooleanArray();
- public RuntimePermissionPersistence(Object lock) {
- mLock = lock;
+ public RuntimePermissionPersistence(Object persistenceLock) {
+ mPersistenceLock = persistenceLock;
}
public boolean areDefaultRuntimPermissionsGrantedLPr(int userId) {
@@ -5321,7 +5192,7 @@
ArrayMap<String, List<PermissionState>> permissionsForPackage = new ArrayMap<>();
ArrayMap<String, List<PermissionState>> permissionsForSharedUser = new ArrayMap<>();
- synchronized (mLock) {
+ synchronized (mPersistenceLock) {
mWriteScheduled.delete(userId);
final int packageCount = mPackages.size();
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
new file mode 100644
index 0000000..09a6e9c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -0,0 +1,564 @@
+/*
+ * 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 static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
+import static android.content.pm.PermissionInfo.PROTECTION_NORMAL;
+import static android.content.pm.PermissionInfo.PROTECTION_SIGNATURE;
+import static android.content.pm.PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM;
+
+import static com.android.server.pm.Settings.ATTR_NAME;
+import static com.android.server.pm.Settings.ATTR_PACKAGE;
+import static com.android.server.pm.Settings.TAG_ITEM;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.Permission;
+import android.content.pm.PermissionInfo;
+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.PackageSettingBase;
+
+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;
+
+public final class BasePermission {
+ static final String TAG = "PackageManager";
+
+ public static final int TYPE_NORMAL = 0;
+ public static final int TYPE_BUILTIN = 1;
+ public static final int TYPE_DYNAMIC = 2;
+ @IntDef(value = {
+ TYPE_NORMAL,
+ TYPE_BUILTIN,
+ TYPE_DYNAMIC,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PermissionType {}
+
+ @IntDef(value = {
+ PROTECTION_DANGEROUS,
+ PROTECTION_NORMAL,
+ PROTECTION_SIGNATURE,
+ PROTECTION_SIGNATURE_OR_SYSTEM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProtectionLevel {}
+
+ final String name;
+
+ @PermissionType final int type;
+
+ String sourcePackageName;
+
+ // TODO: Can we get rid of this? Seems we only use some signature info from the setting
+ PackageSettingBase sourcePackageSetting;
+
+ int protectionLevel;
+
+ PackageParser.Permission perm;
+
+ PermissionInfo pendingPermissionInfo;
+
+ /** UID that owns the definition of this permission */
+ int uid;
+
+ /** Additional GIDs given to apps granted this permission */
+ private int[] gids;
+
+ /**
+ * Flag indicating that {@link #gids} should be adjusted based on the
+ * {@link UserHandle} the granted app is running as.
+ */
+ private boolean perUser;
+
+ public BasePermission(String _name, String _sourcePackageName, @PermissionType int _type) {
+ name = _name;
+ sourcePackageName = _sourcePackageName;
+ type = _type;
+ // Default to most conservative protection level.
+ protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
+ }
+
+ @Override
+ public String toString() {
+ return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
+ + "}";
+ }
+
+ public String getName() {
+ return name;
+ }
+ public int getProtectionLevel() {
+ return protectionLevel;
+ }
+ public String getSourcePackageName() {
+ return sourcePackageName;
+ }
+ public PackageSettingBase getSourcePackageSetting() {
+ return sourcePackageSetting;
+ }
+ public int getType() {
+ return type;
+ }
+ public int getUid() {
+ return uid;
+ }
+ public void setGids(int[] gids, boolean perUser) {
+ this.gids = gids;
+ this.perUser = perUser;
+ }
+ public void setPermission(@Nullable Permission perm) {
+ this.perm = perm;
+ }
+ public void setSourcePackageSetting(PackageSettingBase sourcePackageSetting) {
+ this.sourcePackageSetting = sourcePackageSetting;
+ }
+
+ public int[] computeGids(int userId) {
+ if (perUser) {
+ final int[] userGids = new int[gids.length];
+ for (int i = 0; i < gids.length; i++) {
+ userGids[i] = UserHandle.getUid(userId, gids[i]);
+ }
+ return userGids;
+ } else {
+ return gids;
+ }
+ }
+
+ public int calculateFootprint(BasePermission perm) {
+ if (uid == perm.uid) {
+ return perm.name.length() + perm.perm.info.calculateFootprint();
+ }
+ return 0;
+ }
+
+ public boolean isPermission(Permission perm) {
+ return this.perm == perm;
+ }
+
+ public boolean isDynamic() {
+ return type == TYPE_DYNAMIC;
+ }
+
+
+ public boolean isNormal() {
+ return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+ == PermissionInfo.PROTECTION_NORMAL;
+ }
+ public boolean isRuntime() {
+ return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+ == PermissionInfo.PROTECTION_DANGEROUS;
+ }
+ public boolean isSignature() {
+ return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) ==
+ PermissionInfo.PROTECTION_SIGNATURE;
+ }
+
+ public boolean isAppOp() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
+ }
+ public boolean isDevelopment() {
+ return isSignature()
+ && (protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0;
+ }
+ public boolean isInstaller() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0;
+ }
+ public boolean isInstant() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0;
+ }
+ public boolean isOEM() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_OEM) != 0;
+ }
+ public boolean isPre23() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PRE23) != 0;
+ }
+ public boolean isPreInstalled() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0;
+ }
+ public boolean isPrivileged() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
+ }
+ public boolean isRuntimeOnly() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
+ }
+ public boolean isSetup() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0;
+ }
+ public boolean isVerifier() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0;
+ }
+
+ public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
+ if (!origPackageName.equals(sourcePackageName)) {
+ return;
+ }
+ sourcePackageName = newPackageName;
+ sourcePackageSetting = null;
+ perm = null;
+ if (pendingPermissionInfo != null) {
+ pendingPermissionInfo.packageName = newPackageName;
+ }
+ uid = 0;
+ setGids(null, false);
+ }
+
+ public boolean addToTree(@ProtectionLevel int protectionLevel,
+ @NonNull PermissionInfo info, @NonNull BasePermission tree) {
+ final boolean changed =
+ (this.protectionLevel != protectionLevel
+ || perm == null
+ || uid != tree.uid
+ || !perm.owner.equals(tree.perm.owner)
+ || !comparePermissionInfos(perm.info, info));
+ this.protectionLevel = protectionLevel;
+ info = new PermissionInfo(info);
+ info.protectionLevel = protectionLevel;
+ perm = new PackageParser.Permission(tree.perm.owner, info);
+ perm.info.packageName = tree.perm.info.packageName;
+ uid = tree.uid;
+ return changed;
+ }
+
+ public void updateDynamicPermission(Map<String, BasePermission> permissionTrees) {
+ if (PackageManagerService.DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
+ + getName() + " pkg=" + getSourcePackageName()
+ + " info=" + pendingPermissionInfo);
+ if (sourcePackageSetting == null && pendingPermissionInfo != null) {
+ final BasePermission tree = findPermissionTreeLP(permissionTrees, name);
+ if (tree != null && tree.perm != null) {
+ sourcePackageSetting = tree.sourcePackageSetting;
+ perm = new PackageParser.Permission(tree.perm.owner,
+ new PermissionInfo(pendingPermissionInfo));
+ perm.info.packageName = tree.perm.info.packageName;
+ perm.info.name = name;
+ uid = tree.uid;
+ }
+ }
+ }
+
+ public static BasePermission createOrUpdate(@Nullable BasePermission bp, @NonNull Permission p,
+ @NonNull PackageParser.Package pkg, Map<String, BasePermission> permissionTrees,
+ boolean chatty) {
+ final PackageSettingBase pkgSetting = (PackageSettingBase) pkg.mExtras;
+ // Allow system apps to redefine non-system permissions
+ if (bp != null && !Objects.equals(bp.sourcePackageName, p.info.packageName)) {
+ final boolean currentOwnerIsSystem = (bp.perm != null
+ && bp.perm.owner.isSystemApp());
+ if (p.owner.isSystemApp()) {
+ if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
+ // It's a built-in permission and no owner, take ownership now
+ bp.sourcePackageSetting = pkgSetting;
+ bp.perm = p;
+ bp.uid = pkg.applicationInfo.uid;
+ bp.sourcePackageName = p.info.packageName;
+ p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+ } else if (!currentOwnerIsSystem) {
+ String msg = "New decl " + p.owner + " of permission "
+ + p.info.name + " is system; overriding " + bp.sourcePackageName;
+ PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+ bp = null;
+ }
+ }
+ }
+ if (bp == null) {
+ bp = new BasePermission(p.info.name, p.info.packageName, TYPE_NORMAL);
+ }
+ StringBuilder r = null;
+ if (bp.perm == null) {
+ if (bp.sourcePackageName == null
+ || bp.sourcePackageName.equals(p.info.packageName)) {
+ final BasePermission tree = findPermissionTreeLP(permissionTrees, p.info.name);
+ if (tree == null
+ || tree.sourcePackageName.equals(p.info.packageName)) {
+ bp.sourcePackageSetting = pkgSetting;
+ bp.perm = p;
+ bp.uid = pkg.applicationInfo.uid;
+ bp.sourcePackageName = p.info.packageName;
+ p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
+ }
+ r.append(p.info.name);
+ }
+ } else {
+ Slog.w(TAG, "Permission " + p.info.name + " from package "
+ + p.info.packageName + " ignored: base tree "
+ + tree.name + " is from package "
+ + tree.sourcePackageName);
+ }
+ } else {
+ Slog.w(TAG, "Permission " + p.info.name + " from package "
+ + p.info.packageName + " ignored: original from "
+ + bp.sourcePackageName);
+ }
+ } else if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
+ }
+ r.append("DUP:");
+ r.append(p.info.name);
+ }
+ if (bp.perm == p) {
+ bp.protectionLevel = p.info.protectionLevel;
+ }
+ if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
+ Log.d(TAG, " Permissions: " + r);
+ }
+ return bp;
+ }
+
+ public static BasePermission enforcePermissionTreeLP(
+ Map<String, BasePermission> permissionTrees, String permName, int callingUid) {
+ if (permName != null) {
+ BasePermission bp = findPermissionTreeLP(permissionTrees, permName);
+ if (bp != null) {
+ if (bp.uid == UserHandle.getAppId(callingUid)) {//UserHandle.getAppId(Binder.getCallingUid())) {
+ return bp;
+ }
+ throw new SecurityException("Calling uid " + callingUid
+ + " is not allowed to add to permission tree "
+ + bp.name + " owned by uid " + bp.uid);
+ }
+ }
+ throw new SecurityException("No permission tree found for " + permName);
+ }
+
+ public void enforceDeclaredUsedAndRuntimeOrDevelopment(PackageParser.Package pkg) {
+ int index = pkg.requestedPermissions.indexOf(name);
+ if (index == -1) {
+ throw new SecurityException("Package " + pkg.packageName
+ + " has not requested permission " + name);
+ }
+ if (!isRuntime() && !isDevelopment()) {
+ throw new SecurityException("Permission " + name
+ + " is not a changeable permission type");
+ }
+ }
+
+ private static BasePermission findPermissionTreeLP(
+ Map<String, BasePermission> permissionTrees, String permName) {
+ for (BasePermission bp : permissionTrees.values()) {
+ if (permName.startsWith(bp.name) &&
+ permName.length() > bp.name.length() &&
+ permName.charAt(bp.name.length()) == '.') {
+ return bp;
+ }
+ }
+ return null;
+ }
+
+ public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) {
+ if (groupName == null) {
+ if (perm == null || perm.info.group == null) {
+ return generatePermissionInfo(protectionLevel, flags);
+ }
+ } else {
+ if (perm != null && groupName.equals(perm.info.group)) {
+ return PackageParser.generatePermissionInfo(perm, flags);
+ }
+ }
+ return null;
+ }
+
+ public @NonNull PermissionInfo generatePermissionInfo(int adjustedProtectionLevel, int flags) {
+ final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel;
+ // if we return different protection level, don't use the cached info
+ if (perm != null && !protectionLevelChanged) {
+ return PackageParser.generatePermissionInfo(perm, flags);
+ }
+ final PermissionInfo pi = new PermissionInfo();
+ pi.name = name;
+ pi.packageName = sourcePackageName;
+ pi.nonLocalizedLabel = name;
+ pi.protectionLevel = protectionLevelChanged ? adjustedProtectionLevel : protectionLevel;
+ return pi;
+ }
+
+ 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 sourcePackage = parser.getAttributeValue(null, ATTR_PACKAGE);
+ final String ptype = parser.getAttributeValue(null, "type");
+ if (name == null || sourcePackage == 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.type != TYPE_BUILTIN) {
+ bp = new BasePermission(name.intern(), sourcePackage,
+ dynamic ? TYPE_DYNAMIC : TYPE_NORMAL);
+ }
+ bp.protectionLevel = readInt(parser, null, "protection",
+ PermissionInfo.PROTECTION_NORMAL);
+ bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
+ if (dynamic) {
+ final PermissionInfo pi = new PermissionInfo();
+ pi.packageName = sourcePackage.intern();
+ pi.name = name.intern();
+ pi.icon = readInt(parser, null, "icon", 0);
+ pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
+ pi.protectionLevel = bp.protectionLevel;
+ bp.pendingPermissionInfo = pi;
+ }
+ out.put(bp.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 (sourcePackageName == null) {
+ return;
+ }
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME, name);
+ serializer.attribute(null, ATTR_PACKAGE, sourcePackageName);
+ if (protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
+ serializer.attribute(null, "protection", Integer.toString(protectionLevel));
+ }
+ if (type == BasePermission.TYPE_DYNAMIC) {
+ final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo;
+ if (pi != null) {
+ serializer.attribute(null, "type", "dynamic");
+ if (pi.icon != 0) {
+ serializer.attribute(null, "icon", Integer.toString(pi.icon));
+ }
+ if (pi.nonLocalizedLabel != null) {
+ serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
+ }
+ }
+ }
+ serializer.endTag(null, TAG_ITEM);
+ }
+
+ private static boolean compareStrings(CharSequence s1, CharSequence s2) {
+ if (s1 == null) {
+ return s2 == null;
+ }
+ if (s2 == null) {
+ return false;
+ }
+ if (s1.getClass() != s2.getClass()) {
+ return false;
+ }
+ return s1.equals(s2);
+ }
+
+ private static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
+ if (pi1.icon != pi2.icon) return false;
+ if (pi1.logo != pi2.logo) return false;
+ if (pi1.protectionLevel != pi2.protectionLevel) return false;
+ if (!compareStrings(pi1.name, pi2.name)) return false;
+ if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
+ // We'll take care of setting this one.
+ if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
+ // These are not currently stored in settings.
+ //if (!compareStrings(pi1.group, pi2.group)) return false;
+ //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
+ //if (pi1.labelRes != pi2.labelRes) return false;
+ //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(sourcePackageName)) {
+ return false;
+ }
+ if (permissionNames != null && !permissionNames.contains(name)) {
+ return false;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Permissions:");
+ printedSomething = true;
+ }
+ pw.print(" Permission ["); pw.print(name); pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(this)));
+ pw.println("):");
+ pw.print(" sourcePackage="); pw.println(sourcePackageName);
+ pw.print(" uid="); pw.print(uid);
+ pw.print(" gids="); pw.print(Arrays.toString(
+ computeGids(UserHandle.USER_SYSTEM)));
+ pw.print(" type="); pw.print(type);
+ pw.print(" prot=");
+ pw.println(PermissionInfo.protectionToString(protectionLevel));
+ if (perm != null) {
+ pw.print(" perm="); pw.println(perm);
+ if ((perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
+ || (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
+ pw.print(" flags=0x"); pw.println(Integer.toHexString(perm.info.flags));
+ }
+ }
+ if (sourcePackageSetting != null) {
+ pw.print(" packageSetting="); pw.println(sourcePackageSetting);
+ }
+ if (READ_EXTERNAL_STORAGE.equals(name)) {
+ pw.print(" enforced=");
+ pw.println(readEnforced);
+ }
+ return true;
+ }
+}