Merge changes from topic "required-feature-tag"
* changes: Teach PackageManager to handle <required-(not-)feature> Teach appt2 to handle <required-(not-)feature>
This commit is contained in:
committed by
Android (Google) Code Review
commit
24bb806b68
@@ -1080,14 +1080,57 @@ public class ParsingPackageUtils {
|
||||
}
|
||||
}
|
||||
|
||||
final String requiredFeature = sa.getNonConfigurationString(
|
||||
R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
|
||||
|
||||
final String requiredNotfeature = sa.getNonConfigurationString(
|
||||
R.styleable.AndroidManifestUsesPermission_requiredNotFeature,
|
||||
final ArraySet<String> requiredFeatures = new ArraySet<>();
|
||||
String feature = sa.getNonConfigurationString(
|
||||
com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature,
|
||||
0);
|
||||
if (feature != null) {
|
||||
requiredFeatures.add(feature);
|
||||
}
|
||||
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
final ArraySet<String> requiredNotFeatures = new ArraySet<>();
|
||||
feature = sa.getNonConfigurationString(
|
||||
com.android.internal.R.styleable
|
||||
.AndroidManifestUsesPermission_requiredNotFeature,
|
||||
0);
|
||||
if (feature != null) {
|
||||
requiredNotFeatures.add(feature);
|
||||
}
|
||||
|
||||
final int outerDepth = parser.getDepth();
|
||||
int type;
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& (type != XmlPullParser.END_TAG
|
||||
|| parser.getDepth() > outerDepth)) {
|
||||
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final ParseResult<?> result;
|
||||
switch (parser.getName()) {
|
||||
case "required-feature":
|
||||
result = parseRequiredFeature(input, res, parser);
|
||||
if (result.isSuccess()) {
|
||||
requiredFeatures.add((String) result.getResult());
|
||||
}
|
||||
break;
|
||||
|
||||
case "required-not-feature":
|
||||
result = parseRequiredNotFeature(input, res, parser);
|
||||
if (result.isSuccess()) {
|
||||
requiredNotFeatures.add((String) result.getResult());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
result = ParsingUtils.unknownTag("<uses-permission>", pkg, parser, input);
|
||||
break;
|
||||
}
|
||||
|
||||
if (result.isError()) {
|
||||
return input.error(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Can only succeed from here on out
|
||||
ParseResult<ParsingPackage> success = input.success(pkg);
|
||||
@@ -1100,17 +1143,22 @@ public class ParsingPackageUtils {
|
||||
return success;
|
||||
}
|
||||
|
||||
// Only allow requesting this permission if the platform supports the given feature.
|
||||
if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(
|
||||
requiredFeature)) {
|
||||
return success;
|
||||
}
|
||||
if (mCallback != null) {
|
||||
// Only allow requesting this permission if the platform supports all of the
|
||||
// "required-feature"s.
|
||||
for (int i = requiredFeatures.size() - 1; i >= 0; i--) {
|
||||
if (!mCallback.hasFeature(requiredFeatures.valueAt(i))) {
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
// Only allow requesting this permission if the platform doesn't support the given
|
||||
// feature.
|
||||
if (requiredNotfeature != null && mCallback != null
|
||||
&& mCallback.hasFeature(requiredNotfeature)) {
|
||||
return success;
|
||||
// Only allow requesting this permission if the platform does not supports any of
|
||||
// the "required-not-feature"s.
|
||||
for (int i = requiredNotFeatures.size() - 1; i >= 0; i--) {
|
||||
if (mCallback.hasFeature(requiredNotFeatures.valueAt(i))) {
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pkg.getRequestedPermissions().contains(name)) {
|
||||
@@ -1127,6 +1175,36 @@ public class ParsingPackageUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private ParseResult<String> parseRequiredFeature(ParseInput input, Resources res,
|
||||
AttributeSet attrs) {
|
||||
final TypedArray sa = res.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.AndroidManifestRequiredFeature);
|
||||
try {
|
||||
final String featureName = sa.getString(
|
||||
R.styleable.AndroidManifestRequiredFeature_name);
|
||||
return TextUtils.isEmpty(featureName)
|
||||
? input.error("Feature name is missing from <required-feature> tag.")
|
||||
: input.success(featureName);
|
||||
} finally {
|
||||
sa.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private ParseResult<String> parseRequiredNotFeature(ParseInput input, Resources res,
|
||||
AttributeSet attrs) {
|
||||
final TypedArray sa = res.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.AndroidManifestRequiredNotFeature);
|
||||
try {
|
||||
final String featureName = sa.getString(
|
||||
R.styleable.AndroidManifestRequiredNotFeature_name);
|
||||
return TextUtils.isEmpty(featureName)
|
||||
? input.error("Feature name is missing from <required-not-feature> tag.")
|
||||
: input.success(featureName);
|
||||
} finally {
|
||||
sa.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private static ParseResult<ParsingPackage> parseUsesConfiguration(ParseInput input,
|
||||
ParsingPackage pkg, Resources res, XmlResourceParser parser) {
|
||||
ConfigurationInfo cPref = new ConfigurationInfo();
|
||||
|
||||
@@ -2016,6 +2016,22 @@
|
||||
<attr name="requiredNotFeature" format="string" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- <code>required-feature</code> and <code>required-not-feature</code> elements inside
|
||||
<code>uses-permission<code/> can be used to request the permission based on the fact
|
||||
whether the system supports or does not support certain features.
|
||||
If multiple <code>required-feature</code> and/or <code>required-not-feature</code> elements
|
||||
are present, the permission will be “requested” only if the system supports all of the
|
||||
listed "required-features" and does not support any of the "required-not-features".
|
||||
-->
|
||||
<declare-styleable name="AndroidManifestRequiredFeature">
|
||||
<!-- The name of the feature. -->
|
||||
<attr name="name" />
|
||||
</declare-styleable>
|
||||
<declare-styleable name="AndroidManifestRequiredNotFeature">
|
||||
<!-- The name of the feature. -->
|
||||
<attr name="name" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- The <code>uses-configuration</code> tag specifies
|
||||
a specific hardware configuration value used by the application.
|
||||
For example an application might specify that it requires
|
||||
|
||||
@@ -1063,17 +1063,23 @@ class UsesPermission : public ManifestExtractor::Element {
|
||||
public:
|
||||
UsesPermission() = default;
|
||||
std::string name;
|
||||
std::string requiredFeature;
|
||||
std::string requiredNotFeature;
|
||||
std::vector<std::string> requiredFeatures;
|
||||
std::vector<std::string> requiredNotFeatures;
|
||||
int32_t required = true;
|
||||
int32_t maxSdkVersion = -1;
|
||||
|
||||
void Extract(xml::Element* element) override {
|
||||
name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
|
||||
requiredFeature = GetAttributeStringDefault(
|
||||
FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
|
||||
requiredNotFeature = GetAttributeStringDefault(
|
||||
FindAttribute(element, REQUIRED_NOT_FEATURE_ATTR), "");
|
||||
std::string feature =
|
||||
GetAttributeStringDefault(FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
|
||||
if (!feature.empty()) {
|
||||
requiredFeatures.push_back(feature);
|
||||
}
|
||||
feature = GetAttributeStringDefault(FindAttribute(element, REQUIRED_NOT_FEATURE_ATTR), "");
|
||||
if (!feature.empty()) {
|
||||
requiredNotFeatures.push_back(feature);
|
||||
}
|
||||
|
||||
required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
|
||||
maxSdkVersion = GetAttributeIntegerDefault(
|
||||
FindAttribute(element, MAX_SDK_VERSION_ATTR), -1);
|
||||
@@ -1090,13 +1096,13 @@ class UsesPermission : public ManifestExtractor::Element {
|
||||
if (maxSdkVersion >= 0) {
|
||||
printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
|
||||
}
|
||||
if (!requiredFeature.empty()) {
|
||||
printer->Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data()));
|
||||
}
|
||||
if (!requiredNotFeature.empty()) {
|
||||
printer->Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data()));
|
||||
}
|
||||
printer->Print("\n");
|
||||
for (const std::string& requiredFeature : requiredFeatures) {
|
||||
printer->Print(StringPrintf(" required-feature='%s'\n", requiredFeature.data()));
|
||||
}
|
||||
for (const std::string& requiredNotFeature : requiredNotFeatures) {
|
||||
printer->Print(StringPrintf(" required-not-feature='%s'\n", requiredNotFeature.data()));
|
||||
}
|
||||
if (required == 0) {
|
||||
printer->Print(StringPrintf("optional-permission: name='%s'", name.data()));
|
||||
if (maxSdkVersion >= 0) {
|
||||
@@ -1116,6 +1122,38 @@ class UsesPermission : public ManifestExtractor::Element {
|
||||
}
|
||||
};
|
||||
|
||||
/** Represents <required-feature> elements. **/
|
||||
class RequiredFeature : public ManifestExtractor::Element {
|
||||
public:
|
||||
RequiredFeature() = default;
|
||||
std::string name;
|
||||
|
||||
void Extract(xml::Element* element) override {
|
||||
name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
|
||||
auto parent_stack = extractor()->parent_stack();
|
||||
if (!name.empty() && ElementCast<UsesPermission>(parent_stack[0])) {
|
||||
UsesPermission* uses_permission = ElementCast<UsesPermission>(parent_stack[0]);
|
||||
uses_permission->requiredFeatures.push_back(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Represents <required-not-feature> elements. **/
|
||||
class RequiredNotFeature : public ManifestExtractor::Element {
|
||||
public:
|
||||
RequiredNotFeature() = default;
|
||||
std::string name;
|
||||
|
||||
void Extract(xml::Element* element) override {
|
||||
name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
|
||||
auto parent_stack = extractor()->parent_stack();
|
||||
if (!name.empty() && ElementCast<UsesPermission>(parent_stack[0])) {
|
||||
UsesPermission* uses_permission = ElementCast<UsesPermission>(parent_stack[0]);
|
||||
uses_permission->requiredNotFeatures.push_back(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Represents <uses-permission-sdk-23> elements. **/
|
||||
class UsesPermissionSdk23 : public ManifestExtractor::Element {
|
||||
public:
|
||||
@@ -1845,7 +1883,8 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
|
||||
for (xml::Element* child : element->GetChildElements()) {
|
||||
if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
|
||||
|| child->name == "permission") {
|
||||
auto permission_element = ManifestExtractor::Element::Inflate(this, child);
|
||||
// Inflate the element and its descendants
|
||||
auto permission_element = Visit(child);
|
||||
manifest->AddChild(permission_element);
|
||||
}
|
||||
}
|
||||
@@ -2237,38 +2276,40 @@ T* ElementCast(ManifestExtractor::Element* element) {
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, bool> kTagCheck = {
|
||||
{"action", std::is_base_of<Action, T>::value},
|
||||
{"activity", std::is_base_of<Activity, T>::value},
|
||||
{"application", std::is_base_of<Application, T>::value},
|
||||
{"category", std::is_base_of<Category, T>::value},
|
||||
{"compatible-screens", std::is_base_of<CompatibleScreens, T>::value},
|
||||
{"feature-group", std::is_base_of<FeatureGroup, T>::value},
|
||||
{"input-type", std::is_base_of<InputType, T>::value},
|
||||
{"intent-filter", std::is_base_of<IntentFilter, T>::value},
|
||||
{"meta-data", std::is_base_of<MetaData, T>::value},
|
||||
{"manifest", std::is_base_of<Manifest, T>::value},
|
||||
{"original-package", std::is_base_of<OriginalPackage, T>::value},
|
||||
{"overlay", std::is_base_of<Overlay, T>::value},
|
||||
{"package-verifier", std::is_base_of<PackageVerifier, T>::value},
|
||||
{"permission", std::is_base_of<Permission, T>::value},
|
||||
{"provider", std::is_base_of<Provider, T>::value},
|
||||
{"receiver", std::is_base_of<Receiver, T>::value},
|
||||
{"screen", std::is_base_of<Screen, T>::value},
|
||||
{"service", std::is_base_of<Service, T>::value},
|
||||
{"supports-gl-texture", std::is_base_of<SupportsGlTexture, T>::value},
|
||||
{"supports-input", std::is_base_of<SupportsInput, T>::value},
|
||||
{"supports-screens", std::is_base_of<SupportsScreen, T>::value},
|
||||
{"uses-configuration", std::is_base_of<UsesConfiguarion, T>::value},
|
||||
{"uses-feature", std::is_base_of<UsesFeature, T>::value},
|
||||
{"uses-permission", std::is_base_of<UsesPermission, T>::value},
|
||||
{"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
|
||||
{"uses-library", std::is_base_of<UsesLibrary, T>::value},
|
||||
{"uses-package", std::is_base_of<UsesPackage, T>::value},
|
||||
{"static-library", std::is_base_of<StaticLibrary, T>::value},
|
||||
{"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
|
||||
{"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
|
||||
{"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
|
||||
{"uses-native-library", std::is_base_of<UsesNativeLibrary, T>::value},
|
||||
{"action", std::is_base_of<Action, T>::value},
|
||||
{"activity", std::is_base_of<Activity, T>::value},
|
||||
{"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
|
||||
{"application", std::is_base_of<Application, T>::value},
|
||||
{"category", std::is_base_of<Category, T>::value},
|
||||
{"compatible-screens", std::is_base_of<CompatibleScreens, T>::value},
|
||||
{"feature-group", std::is_base_of<FeatureGroup, T>::value},
|
||||
{"input-type", std::is_base_of<InputType, T>::value},
|
||||
{"intent-filter", std::is_base_of<IntentFilter, T>::value},
|
||||
{"meta-data", std::is_base_of<MetaData, T>::value},
|
||||
{"manifest", std::is_base_of<Manifest, T>::value},
|
||||
{"original-package", std::is_base_of<OriginalPackage, T>::value},
|
||||
{"overlay", std::is_base_of<Overlay, T>::value},
|
||||
{"package-verifier", std::is_base_of<PackageVerifier, T>::value},
|
||||
{"permission", std::is_base_of<Permission, T>::value},
|
||||
{"provider", std::is_base_of<Provider, T>::value},
|
||||
{"receiver", std::is_base_of<Receiver, T>::value},
|
||||
{"required-feature", std::is_base_of<RequiredFeature, T>::value},
|
||||
{"required-not-feature", std::is_base_of<RequiredNotFeature, T>::value},
|
||||
{"screen", std::is_base_of<Screen, T>::value},
|
||||
{"service", std::is_base_of<Service, T>::value},
|
||||
{"static-library", std::is_base_of<StaticLibrary, T>::value},
|
||||
{"supports-gl-texture", std::is_base_of<SupportsGlTexture, T>::value},
|
||||
{"supports-input", std::is_base_of<SupportsInput, T>::value},
|
||||
{"supports-screens", std::is_base_of<SupportsScreen, T>::value},
|
||||
{"uses-configuration", std::is_base_of<UsesConfiguarion, T>::value},
|
||||
{"uses-feature", std::is_base_of<UsesFeature, T>::value},
|
||||
{"uses-library", std::is_base_of<UsesLibrary, T>::value},
|
||||
{"uses-native-library", std::is_base_of<UsesNativeLibrary, T>::value},
|
||||
{"uses-package", std::is_base_of<UsesPackage, T>::value},
|
||||
{"uses-permission", std::is_base_of<UsesPermission, T>::value},
|
||||
{"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
|
||||
{"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
|
||||
{"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
|
||||
};
|
||||
|
||||
auto check = kTagCheck.find(element->tag());
|
||||
@@ -2288,39 +2329,41 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
|
||||
const std::unordered_map<std::string,
|
||||
std::function<std::unique_ptr<ManifestExtractor::Element>()>>
|
||||
kTagCheck = {
|
||||
{"action", &CreateType<Action>},
|
||||
{"activity", &CreateType<Activity>},
|
||||
{"application", &CreateType<Application>},
|
||||
{"category", &CreateType<Category>},
|
||||
{"compatible-screens", &CreateType<CompatibleScreens>},
|
||||
{"feature-group", &CreateType<FeatureGroup>},
|
||||
{"input-type", &CreateType<InputType>},
|
||||
{"intent-filter",&CreateType<IntentFilter>},
|
||||
{"manifest", &CreateType<Manifest>},
|
||||
{"meta-data", &CreateType<MetaData>},
|
||||
{"original-package", &CreateType<OriginalPackage>},
|
||||
{"overlay", &CreateType<Overlay>},
|
||||
{"package-verifier", &CreateType<PackageVerifier>},
|
||||
{"permission", &CreateType<Permission>},
|
||||
{"provider", &CreateType<Provider>},
|
||||
{"receiver", &CreateType<Receiver>},
|
||||
{"screen", &CreateType<Screen>},
|
||||
{"service", &CreateType<Service>},
|
||||
{"supports-gl-texture", &CreateType<SupportsGlTexture>},
|
||||
{"supports-input", &CreateType<SupportsInput>},
|
||||
{"supports-screens", &CreateType<SupportsScreen>},
|
||||
{"uses-configuration", &CreateType<UsesConfiguarion>},
|
||||
{"uses-feature", &CreateType<UsesFeature>},
|
||||
{"uses-permission", &CreateType<UsesPermission>},
|
||||
{"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
|
||||
{"uses-library", &CreateType<UsesLibrary>},
|
||||
{"static-library", &CreateType<StaticLibrary>},
|
||||
{"uses-static-library", &CreateType<UsesStaticLibrary>},
|
||||
{"uses-package", &CreateType<UsesPackage>},
|
||||
{"additional-certificate", &CreateType<AdditionalCertificate>},
|
||||
{"uses-sdk", &CreateType<UsesSdkBadging>},
|
||||
{"uses-native-library", &CreateType<UsesNativeLibrary>},
|
||||
};
|
||||
{"action", &CreateType<Action>},
|
||||
{"activity", &CreateType<Activity>},
|
||||
{"additional-certificate", &CreateType<AdditionalCertificate>},
|
||||
{"application", &CreateType<Application>},
|
||||
{"category", &CreateType<Category>},
|
||||
{"compatible-screens", &CreateType<CompatibleScreens>},
|
||||
{"feature-group", &CreateType<FeatureGroup>},
|
||||
{"input-type", &CreateType<InputType>},
|
||||
{"intent-filter", &CreateType<IntentFilter>},
|
||||
{"manifest", &CreateType<Manifest>},
|
||||
{"meta-data", &CreateType<MetaData>},
|
||||
{"original-package", &CreateType<OriginalPackage>},
|
||||
{"overlay", &CreateType<Overlay>},
|
||||
{"package-verifier", &CreateType<PackageVerifier>},
|
||||
{"permission", &CreateType<Permission>},
|
||||
{"provider", &CreateType<Provider>},
|
||||
{"receiver", &CreateType<Receiver>},
|
||||
{"required-feature", &CreateType<RequiredFeature>},
|
||||
{"required-not-feature", &CreateType<RequiredNotFeature>},
|
||||
{"screen", &CreateType<Screen>},
|
||||
{"service", &CreateType<Service>},
|
||||
{"static-library", &CreateType<StaticLibrary>},
|
||||
{"supports-gl-texture", &CreateType<SupportsGlTexture>},
|
||||
{"supports-input", &CreateType<SupportsInput>},
|
||||
{"supports-screens", &CreateType<SupportsScreen>},
|
||||
{"uses-configuration", &CreateType<UsesConfiguarion>},
|
||||
{"uses-feature", &CreateType<UsesFeature>},
|
||||
{"uses-library", &CreateType<UsesLibrary>},
|
||||
{"uses-native-library", &CreateType<UsesNativeLibrary>},
|
||||
{"uses-package", &CreateType<UsesPackage>},
|
||||
{"uses-permission", &CreateType<UsesPermission>},
|
||||
{"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
|
||||
{"uses-sdk", &CreateType<UsesSdkBadging>},
|
||||
{"uses-static-library", &CreateType<UsesStaticLibrary>},
|
||||
};
|
||||
|
||||
// Attempt to map the xml tag to a element inflater
|
||||
std::unique_ptr<ManifestExtractor::Element> element;
|
||||
|
||||
@@ -393,6 +393,8 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
|
||||
manifest_action["protected-broadcast"];
|
||||
manifest_action["adopt-permissions"];
|
||||
manifest_action["uses-permission"];
|
||||
manifest_action["uses-permission"]["required-feature"].Action(RequiredNameIsNotEmpty);
|
||||
manifest_action["uses-permission"]["required-not-feature"].Action(RequiredNameIsNotEmpty);
|
||||
manifest_action["uses-permission-sdk-23"];
|
||||
manifest_action["permission"];
|
||||
manifest_action["permission"]["meta-data"] = meta_data_action;
|
||||
|
||||
Reference in New Issue
Block a user