Teach appt2 to handle <required-(not-)feature>
Introducing 'required-feature' and 'requred-not-feature' tags that could
be used "inside" 'uses-permission' elements.
Elements of both types should have non-empty 'android:name' attribute to
specify the name of the feature.
Bug: 168079571
Test: make aapt2
Test: make aapt2_tests
Test: out/host/linux-x86/nativetest64/aapt2_tests/aapt2_tests
Test: create AndroidManifest.xml with <required(-not)-feature>
Test: aapt2 link -o out.apk -I $ANDROID_SDK/platforms/android-30/android.jar --manifest AndroidManifest.xml
Test: aapt2 dump badging out.apk
Test: appt2 dump permissions out.apk
Change-Id: I67ba0731daa6d31cd976b922217853f159cf7c3a
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 7497869..8862405 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -1063,17 +1063,23 @@
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 @@
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 @@
}
};
+/** 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 @@
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 @@
}
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 @@
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;