Merge "Implement issue #34842682: Add ability to limit permissions based on features"

This commit is contained in:
Dianne Hackborn
2017-03-02 18:31:11 +00:00
committed by Android (Google) Code Review
11 changed files with 142 additions and 47 deletions

View File

@@ -1005,7 +1005,7 @@ package android {
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
field public static final int primaryContentAlpha = 16843367; // 0x1010267
field public static final int primaryContentAlpha = 16844117; // 0x1010555
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1061,7 +1061,9 @@ package android {
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
field public static final int requiredFeature = 16844119; // 0x1010557
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
field public static final int requiredNotFeature = 16844120; // 0x1010558
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1130,7 +1132,7 @@ package android {
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
field public static final int secondaryContentAlpha = 16844118; // 0x1010556
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468

View File

@@ -1117,7 +1117,7 @@ package android {
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
field public static final int primaryContentAlpha = 16843367; // 0x1010267
field public static final int primaryContentAlpha = 16844117; // 0x1010555
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1173,7 +1173,9 @@ package android {
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
field public static final int requiredFeature = 16844119; // 0x1010557
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
field public static final int requiredNotFeature = 16844120; // 0x1010558
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1246,7 +1248,7 @@ package android {
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
field public static final int secondaryContentAlpha = 16844118; // 0x1010556
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468

View File

@@ -1005,7 +1005,7 @@ package android {
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
field public static final int primaryContentAlpha = 16843367; // 0x1010267
field public static final int primaryContentAlpha = 16844117; // 0x1010555
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1061,7 +1061,9 @@ package android {
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
field public static final int requiredFeature = 16844119; // 0x1010557
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
field public static final int requiredNotFeature = 16844120; // 0x1010558
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1130,7 +1132,7 @@ package android {
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
field public static final int secondaryContentAlpha = 16844118; // 0x1010556
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468

View File

@@ -5000,6 +5000,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) {

View File

@@ -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,

View File

@@ -1534,6 +1534,14 @@
of Android higher than the number given here, the permission will not
be requested. -->
<attr name="maxSdkVersion" format="integer" />
<!-- Optional: the system must support this feature for the permission to be
requested. If it doesn't support the feature, it will be as if the manifest didn't
request it at all. -->
<attr name="requiredFeature" format="string" />
<!-- Optional: the system must NOT support this feature for the permission to be
requested. If it does support the feature, it will be as if the manifest didn't
request it at all. -->
<attr name="requiredNotFeature" format="string" />
</declare-styleable>
<!-- The <code>uses-configuration</code> tag specifies

View File

@@ -2797,6 +2797,10 @@
<public name="fontProviderAuthority" />
<public name="fontProviderQuery" />
<public name="autoFillMode" />
<public name="primaryContentAlpha" />
<public name="secondaryContentAlpha" />
<public name="requiredFeature" />
<public name="requiredNotFeature" />
</public-group>
<public-group type="style" first-id="0x010302e0">
@@ -2806,9 +2810,6 @@
<public name="textAssist" />
</public-group>
<public type="attr" name="primaryContentAlpha" />
<public type="attr" name="secondaryContentAlpha" />
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE

View File

@@ -746,6 +746,12 @@ public class PackageManagerService extends IPackageManager.Stub {
@GuardedBy("mPackages")
final SparseArray<Map<String, Integer>> mChangedPackagesSequenceNumbers = new SparseArray<>();
final PackageParser.Callback mPackageParserCallback = new PackageParser.Callback() {
@Override public boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
};
public static final class SharedLibraryEntry {
public final String path;
public final String apk;
@@ -7584,7 +7590,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ " flags=0x" + Integer.toHexString(parseFlags));
}
ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir);
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, mPackageParserCallback);
// Submit files for parsing in parallel
int fileCount = 0;
@@ -7753,6 +7759,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
@@ -9616,7 +9623,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/**
* Asserts the parsed package is valid according to the given policy. If the
* package is invalid, for whatever reason, throws {@link PackgeManagerException}.
* package is invalid, for whatever reason, throws {@link PackageManagerException}.
* <p>
* Implementation detail: This method must NOT have any side effects. It would
* ideally be static, but, it requires locks to read system state.
@@ -12814,7 +12821,7 @@ public class PackageManagerService extends IPackageManager.Stub {
* By having a field variable, we're able to track filter ordering as soon as
* a non-zero order is defined. Otherwise, multiple loops across the result set
* would be needed to apply ordering. If the intent resolver becomes re-entrant,
* this needs to be contained entirely within {@link #filterResults()}.
* this needs to be contained entirely within {@link #filterResults}.
*/
final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>();
@@ -16636,6 +16643,7 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;

View File

@@ -46,6 +46,7 @@ class ParallelPackageParser implements AutoCloseable {
private final boolean mOnlyCore;
private final DisplayMetrics mMetrics;
private final File mCacheDir;
private final PackageParser.Callback mPackageParserCallback;
private volatile String mInterruptedInThread;
private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
@@ -54,11 +55,12 @@ class ParallelPackageParser implements AutoCloseable {
"package-parsing-thread", Process.THREAD_PRIORITY_FOREGROUND);
ParallelPackageParser(String[] separateProcesses, boolean onlyCoreApps,
DisplayMetrics metrics, File cacheDir) {
DisplayMetrics metrics, File cacheDir, PackageParser.Callback callback) {
mSeparateProcesses = separateProcesses;
mOnlyCore = onlyCoreApps;
mMetrics = metrics;
mCacheDir = cacheDir;
mPackageParserCallback = callback;
}
static class ParseResult {
@@ -110,6 +112,7 @@ class ParallelPackageParser implements AutoCloseable {
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
pp.setCacheDir(mCacheDir);
pp.setCallback(mPackageParserCallback);
pr.scanFile = scanFile;
pr.pkg = parsePackage(pp, scanFile, parseFlags);
} catch (Throwable e) {

View File

@@ -69,7 +69,7 @@ public class ParallelPackageParserTest {
class TestParallelPackageParser extends ParallelPackageParser {
TestParallelPackageParser() {
super(null, false, null, null);
super(null, false, null, null, null);
}
@Override

View File

@@ -309,6 +309,8 @@ enum {
CATEGORY_ATTR = 0x010103e8,
BANNER_ATTR = 0x10103f2,
ISGAME_ATTR = 0x10103f4,
REQUIRED_FEATURE_ATTR = 0x1010557,
REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
};
String8 getComponentName(String8 &pkgName, String8 &componentName) {
@@ -366,11 +368,19 @@ static void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
printf("\n");
}
static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1,
const String8& requiredFeature = String8::empty(),
const String8& requiredNotFeature = String8::empty()) {
printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
if (maxSdkVersion != -1) {
printf(" maxSdkVersion='%d'", maxSdkVersion);
}
if (requiredFeature.length() > 0) {
printf(" requiredFeature='%s'", requiredFeature.string());
}
if (requiredNotFeature.length() > 0) {
printf(" requiredNotFeature='%s'", requiredNotFeature.string());
}
printf("\n");
if (optional) {
@@ -1545,6 +1555,10 @@ int doDump(Bundle* bundle)
const int32_t maxSdkVersion =
AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, -1);
const String8 requiredFeature = AaptXml::getAttribute(tree,
REQUIRED_FEATURE_ATTR, &error);
const String8 requiredNotFeature = AaptXml::getAttribute(tree,
REQUIRED_NOT_FEATURE_ATTR, &error);
if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
hasWriteExternalStoragePermission = true;
@@ -1565,7 +1579,7 @@ int doDump(Bundle* bundle)
printUsesPermission(name,
AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
maxSdkVersion);
maxSdkVersion, requiredFeature, requiredNotFeature);
} else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);