summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2017-02-28 17:37:35 -0800
committerDianne Hackborn <hackbod@google.com>2017-03-01 12:40:57 -0800
commitcd154e95353e7af11314d2339500d6c7f85e181a (patch)
tree4e04c20b2ff5fde52da63511ba1a68a96ab6835b /core/java/android
parenteb422ead0cd7101855db4bff50cb71321cee2377 (diff)
Implement issue #34842682: Add ability to limit permissions based on features
Two new attributes for <uses-permission>: android:requiredFeature and android:requiredNotFeature. Also update aapt to include this information in badging: uses-permission: name='android.content.cts.REQUIRED_NOT_FEATURE_UNDEFINED' requiredNotFeature='android.software.cts.undefined' uses-permission: name='android.content.cts.REQUIRED_MULTI_DENY' requiredFeature='android.software.cts.undefined' requiredNotFeature='android.software.cts' Test: new PermissionFeatureTest suite. Change-Id: Icc1f815a4675ae9dd2cb7f61730ab28b5c11228a
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/content/pm/PackageManager.java1
-rw-r--r--core/java/android/content/pm/PackageParser.java116
2 files changed, 86 insertions, 31 deletions
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0482f5136b0c..85f6169412b0 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4983,6 +4983,7 @@ public abstract class PackageManager {
*/
public PackageInfo getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags) {
final PackageParser parser = new PackageParser();
+ parser.setCallback(new PackageParser.CallbackImpl(this));
final File apkFile = new File(archiveFilePath);
try {
if ((flags & (MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE)) != 0) {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f801e4547658..60cc6b06bf11 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -285,6 +285,7 @@ public class PackageParser {
private String[] mSeparateProcesses;
private boolean mOnlyCoreApps;
private DisplayMetrics mMetrics;
+ private Callback mCallback;
private File mCacheDir;
private static final int SDK_VERSION = Build.VERSION.SDK_INT;
@@ -506,6 +507,37 @@ public class PackageParser {
mCacheDir = cacheDir;
}
+ /**
+ * Callback interface for retrieving information that may be needed while parsing
+ * a package.
+ */
+ public interface Callback {
+ boolean hasFeature(String feature);
+ }
+
+ /**
+ * Standard implementation of {@link Callback} on top of the public {@link PackageManager}
+ * class.
+ */
+ public static final class CallbackImpl implements Callback {
+ private final PackageManager mPm;
+
+ public CallbackImpl(PackageManager pm) {
+ mPm = pm;
+ }
+
+ @Override public boolean hasFeature(String feature) {
+ return mPm.hasSystemFeature(feature);
+ }
+ }
+
+ /**
+ * Set the {@link Callback} that can be used while parsing.
+ */
+ public void setCallback(Callback cb) {
+ mCallback = cb;
+ }
+
public static final boolean isApkFile(File file) {
return isApkPath(file.getName());
}
@@ -2079,15 +2111,15 @@ public class PackageParser {
return null;
}
} else if (tagName.equals(TAG_PERMISSION_GROUP)) {
- if (parsePermissionGroup(pkg, flags, res, parser, outError) == null) {
+ if (!parsePermissionGroup(pkg, flags, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION)) {
- if (parsePermission(pkg, res, parser, outError) == null) {
+ if (!parsePermission(pkg, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION_TREE)) {
- if (parsePermissionTree(pkg, res, parser, outError) == null) {
+ if (!parsePermissionTree(pkg, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_USES_PERMISSION)) {
@@ -2708,22 +2740,44 @@ public class PackageParser {
}
}
+ final String requiredFeature = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
+
+ final String requiredNotfeature = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredNotFeature, 0);
+
sa.recycle();
- if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
- if (name != null) {
- int index = pkg.requestedPermissions.indexOf(name);
- if (index == -1) {
- pkg.requestedPermissions.add(name.intern());
- } else {
- Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
- + name + " in package: " + pkg.packageName + " at: "
- + parser.getPositionDescription());
- }
- }
+ XmlUtils.skipCurrentTag(parser);
+
+ if (name == null) {
+ return true;
+ }
+
+ if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
+ return true;
+ }
+
+ // Only allow requesting this permission if the platform supports the given feature.
+ if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(requiredFeature)) {
+ return true;
+ }
+
+ // Only allow requesting this permission if the platform doesn't support the given feature.
+ if (requiredNotfeature != null && mCallback != null
+ && mCallback.hasFeature(requiredNotfeature)) {
+ return true;
+ }
+
+ int index = pkg.requestedPermissions.indexOf(name);
+ if (index == -1) {
+ pkg.requestedPermissions.add(name.intern());
+ } else {
+ Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
+ + name + " in package: " + pkg.packageName + " at: "
+ + parser.getPositionDescription());
}
- XmlUtils.skipCurrentTag(parser);
return true;
}
@@ -2951,7 +3005,7 @@ public class PackageParser {
return true;
}
- private PermissionGroup parsePermissionGroup(Package owner, int flags, Resources res,
+ private boolean parsePermissionGroup(Package owner, int flags, Resources res,
XmlResourceParser parser, String[] outError)
throws XmlPullParserException, IOException {
PermissionGroup perm = new PermissionGroup(owner);
@@ -2968,7 +3022,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
perm.info.descriptionRes = sa.getResourceId(
@@ -2987,22 +3041,22 @@ public class PackageParser {
if (!parseAllMetaData(res, parser, "<permission-group>", perm,
outError)) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
owner.permissionGroups.add(perm);
- return perm;
+ return true;
}
- private Permission parsePermission(Package owner, Resources res,
+ private boolean parsePermission(Package owner, Resources res,
XmlResourceParser parser, String[] outError)
throws XmlPullParserException, IOException {
- Permission perm = new Permission(owner);
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestPermission);
+ Permission perm = new Permission(owner);
if (!parsePackageItemInfo(owner, perm.info, outError,
"<permission>", sa, true /*nameRequired*/,
com.android.internal.R.styleable.AndroidManifestPermission_name,
@@ -3013,7 +3067,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
// Note: don't allow this value to be a reference to a resource
@@ -3040,7 +3094,7 @@ public class PackageParser {
if (perm.info.protectionLevel == -1) {
outError[0] = "<permission> does not specify protectionLevel";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
@@ -3052,21 +3106,21 @@ public class PackageParser {
outError[0] = "<permission> protectionLevel specifies a non-ephemeral flag but is "
+ "not based on signature type";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
}
if (!parseAllMetaData(res, parser, "<permission>", perm, outError)) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
owner.permissions.add(perm);
- return perm;
+ return true;
}
- private Permission parsePermissionTree(Package owner, Resources res,
+ private boolean parsePermissionTree(Package owner, Resources res,
XmlResourceParser parser, String[] outError)
throws XmlPullParserException, IOException {
Permission perm = new Permission(owner);
@@ -3084,7 +3138,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
sa.recycle();
@@ -3097,7 +3151,7 @@ public class PackageParser {
outError[0] = "<permission-tree> name has less than three segments: "
+ perm.info.name;
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
perm.info.descriptionRes = 0;
@@ -3107,12 +3161,12 @@ public class PackageParser {
if (!parseAllMetaData(res, parser, "<permission-tree>", perm,
outError)) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
owner.permissions.add(perm);
- return perm;
+ return true;
}
private Instrumentation parseInstrumentation(Package owner, Resources res,