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;