Extend DumpManifest unit to export badging data into proto.

Bug: b/228950123
Test: Dump_test.cpp
Change-Id: I3c228767b435d0e31f1eec1f34daeec1065628d0
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 64a9441..e36112d 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -17,8 +17,10 @@
 #include "DumpManifest.h"
 
 #include <algorithm>
+#include <array>
 #include <memory>
 #include <set>
+#include <string_view>
 #include <vector>
 
 #include "LoadedApk.h"
@@ -114,10 +116,101 @@
   return el->FindAttribute(package, name);
 }
 
+class Architectures {
+ public:
+  std::set<std::string> architectures;
+  std::set<std::string> alt_architectures;
+
+  void Print(text::Printer* printer) {
+    if (!architectures.empty()) {
+      printer->Print("native-code:");
+      for (auto& arch : architectures) {
+        printer->Print(StringPrintf(" '%s'", arch.data()));
+      }
+      printer->Print("\n");
+    }
+    if (!alt_architectures.empty()) {
+      printer->Print("alt-native-code:");
+      for (auto& arch : alt_architectures) {
+        printer->Print(StringPrintf(" '%s'", arch.data()));
+      }
+      printer->Print("\n");
+    }
+  }
+
+  void ToProto(pb::Badging* out_badging) {
+    auto out_architectures = out_badging->mutable_architectures();
+    for (auto& arch : architectures) {
+      out_architectures->add_architectures(arch);
+    }
+    for (auto& arch : alt_architectures) {
+      out_architectures->add_alt_architectures(arch);
+    }
+  }
+};
+
+const static std::array<std::string_view, 14> printable_components{"app-widget",
+                                                                   "device-admin",
+                                                                   "ime",
+                                                                   "wallpaper",
+                                                                   "accessibility",
+                                                                   "print-service",
+                                                                   "payment",
+                                                                   "search",
+                                                                   "document-provider",
+                                                                   "launcher",
+                                                                   "notification-listener",
+                                                                   "dream",
+                                                                   "camera",
+                                                                   "camera-secure"};
+
+class Components {
+ public:
+  std::set<std::string, std::less<>> discovered_components;
+  bool other_activities = false;
+  bool other_receivers = false;
+  bool other_services = false;
+
+  void Print(text::Printer* printer) {
+    for (auto& component : printable_components) {
+      if (discovered_components.find(component) != discovered_components.end()) {
+        printer->Print(StringPrintf("provides-component:'%s'\n", component.data()));
+      }
+    }
+    // Print presence of main activity
+    if (discovered_components.find("main") != discovered_components.end()) {
+      printer->Print("main\n");
+    }
+
+    if (other_activities) {
+      printer->Print("other-activities\n");
+    }
+    if (other_receivers) {
+      printer->Print("other-receivers\n");
+    }
+    if (other_services) {
+      printer->Print("other-services\n");
+    }
+  }
+
+  void ToProto(pb::Badging* out_badging) {
+    auto out_components = out_badging->mutable_components();
+    for (auto& component : printable_components) {
+      auto discovered = discovered_components.find(component);
+      if (discovered != discovered_components.end()) {
+        out_components->add_provided_components(*discovered);
+      }
+    }
+    out_components->set_main(discovered_components.find("main") != discovered_components.end());
+    out_components->set_other_activities(other_activities);
+    out_components->set_other_receivers(other_receivers);
+    out_components->set_other_services(other_services);
+  }
+};
+
 class CommonFeatureGroup;
-class Architectures;
-class SupportsScreen;
 class FeatureGroup;
+class SupportsScreen;
 
 class ManifestExtractor {
  public:
@@ -133,7 +226,12 @@
     static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
 
     /** Writes out the extracted contents of the element. */
-    virtual void Print(text::Printer* printer) { }
+    virtual void Print(text::Printer* printer) {
+    }
+
+    /** Saves extracted information into Badging proto. */
+    virtual void ToProto(pb::Badging* out_badging) {
+    }
 
     /** Adds an element to the list of children of the element. */
     void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); }
@@ -345,6 +443,7 @@
 
   bool Extract(IDiagnostics* diag);
   bool Dump(text::Printer* printer);
+  bool DumpProto(pb::Badging* out_badging);
 
   /** Recursively visit the xml element tree and return a processed badging element tree. */
   std::unique_ptr<Element> Visit(xml::Element* element);
@@ -402,12 +501,9 @@
 
   std::unique_ptr<ManifestExtractor::Element> root_element_;
   std::vector<std::unique_ptr<ManifestExtractor::Element>> implied_permissions_;
-  std::set<std::string> components_;
   std::vector<FeatureGroup*> feature_groups_;
-  bool other_activities_ = false;
-  bool other_receivers_ = false;
-  bool other_services_ = false;
-  std::unique_ptr<Architectures> architectures_ = util::make_unique<Architectures>();
+  Components components_;
+  Architectures architectures_;
   const SupportsScreen* supports_screen_;
 };
 
@@ -480,6 +576,45 @@
     installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR));
   }
 
+  void ToProto(pb::Badging* out_badging) override {
+    auto out_package = out_badging->mutable_package();
+    out_package->set_package(package);
+    out_package->set_version_code(versionCode);
+    out_package->set_version_name(versionName);
+    if (compilesdkVersion) {
+      out_package->set_compile_sdk_version(*compilesdkVersion);
+    }
+    if (compilesdkVersionCodename) {
+      out_package->set_compile_sdk_version_codename(*compilesdkVersionCodename);
+    }
+    if (platformVersionName) {
+      out_package->set_platform_version_name(*platformVersionName);
+    } else if (platformVersionNameInt) {
+      out_package->set_platform_version_name(std::to_string(*platformVersionNameInt));
+    }
+    if (platformVersionCode) {
+      out_package->set_platform_version_code(*platformVersionCode);
+    } else if (platformVersionCodeInt) {
+      out_package->set_platform_version_code(std::to_string(*platformVersionCodeInt));
+    }
+
+    if (installLocation) {
+      switch (*installLocation) {
+        case 0:
+          out_package->set_install_location(pb::PackageInfo_InstallLocation_AUTO);
+          break;
+        case 1:
+          out_package->set_install_location(pb::PackageInfo_InstallLocation_INTERNAL_ONLY);
+          break;
+        case 2:
+          out_package->set_install_location(pb::PackageInfo_InstallLocation_PREFER_EXTERNAL);
+          break;
+        default:
+          break;
+      }
+    }
+  }
+
   void Print(text::Printer* printer) override {
     if (only_package_name) {
       printer->Println(StringPrintf("package: %s", package.data()));
@@ -624,6 +759,27 @@
       printer->Print("application-debuggable\n");
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    auto application = out_badging->mutable_application();
+    application->set_label(android::ResTable::normalizeForOutput(label.data()));
+    application->set_icon(icon);
+    application->set_banner(banner);
+    application->set_test_only(test_only != 0);
+    application->set_game(is_game != 0);
+    application->set_debuggable(debuggable != 0);
+
+    auto out_locale_labels = application->mutable_locale_labels();
+    for (auto& p : locale_labels) {
+      if (!p.first.empty()) {
+        (*out_locale_labels)[p.first] = p.second;
+      }
+    }
+    auto out_density_icons = application->mutable_density_icons();
+    for (auto& p : density_icons) {
+      (*out_density_icons)[p.first] = p.second;
+    }
+  }
 };
 
 /** Represents <uses-sdk> elements. **/
@@ -673,6 +829,23 @@
       printer->Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    auto out_sdks = out_badging->mutable_uses_sdk();
+    if (min_sdk) {
+      out_sdks->set_min_sdk_version(*min_sdk);
+    } else if (min_sdk_name) {
+      out_sdks->set_min_sdk_version_name(*min_sdk_name);
+    }
+    if (max_sdk) {
+      out_sdks->set_max_sdk_version(*max_sdk);
+    }
+    if (target_sdk) {
+      out_sdks->set_target_sdk_version(*target_sdk);
+    } else if (target_sdk_name) {
+      out_sdks->set_target_sdk_version_name(*target_sdk_name);
+    }
+  }
 };
 
 /** Represents <uses-configuration> elements. **/
@@ -717,6 +890,15 @@
     }
     printer->Print("\n");
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    auto out_configuration = out_badging->mutable_uses_configuration();
+    out_configuration->set_req_touch_screen(req_touch_screen);
+    out_configuration->set_req_keyboard_type(req_keyboard_type);
+    out_configuration->set_req_hard_keyboard(req_hard_keyboard);
+    out_configuration->set_req_navigation(req_navigation);
+    out_configuration->set_req_five_way_nav(req_five_way_nav);
+  }
 };
 
 /** Represents <supports-screen> elements. **/
@@ -760,53 +942,23 @@
   }
 
   void PrintScreens(text::Printer* printer, int32_t target_sdk) const {
-    int32_t small_screen_temp = small_screen;
-    int32_t normal_screen_temp  = normal_screen;
-    int32_t large_screen_temp  = large_screen;
-    int32_t xlarge_screen_temp  = xlarge_screen;
-    int32_t any_density_temp  = any_density;
-
-    // Determine default values for any unspecified screen sizes,
-    // based on the target SDK of the package.  As of 4 (donut)
-    // the screen size support was introduced, so all default to
-    // enabled.
-    if (small_screen_temp  > 0) {
-      small_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
-    }
-    if (normal_screen_temp  > 0) {
-      normal_screen_temp  = -1;
-    }
-    if (large_screen_temp  > 0) {
-      large_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
-    }
-    if (xlarge_screen_temp  > 0) {
-      // Introduced in Gingerbread.
-      xlarge_screen_temp = target_sdk >= SDK_GINGERBREAD ? -1 : 0;
-    }
-    if (any_density_temp  > 0) {
-      any_density_temp = (target_sdk >= SDK_DONUT || requires_smallest_width_dp > 0 ||
-                          compatible_width_limit_dp > 0)
-                             ? -1
-                             : 0;
-    }
-
     // Print the formatted screen info
     printer->Print("supports-screens:");
-    if (small_screen_temp  != 0) {
+    if (IsSmallScreenSupported(target_sdk)) {
       printer->Print(" 'small'");
     }
-    if (normal_screen_temp  != 0) {
+    if (normal_screen != 0) {
       printer->Print(" 'normal'");
     }
-    if (large_screen_temp   != 0) {
+    if (IsLargeScreenSupported(target_sdk)) {
       printer->Print(" 'large'");
     }
-    if (xlarge_screen_temp  != 0) {
+    if (IsXLargeScreenSupported(target_sdk)) {
       printer->Print(" 'xlarge'");
     }
     printer->Print("\n");
     printer->Print(StringPrintf("supports-any-density: '%s'\n",
-                                (any_density_temp ) ? "true" : "false"));
+                                (IsAnyDensitySupported(target_sdk)) ? "true" : "false"));
     if (requires_smallest_width_dp > 0) {
       printer->Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
     }
@@ -817,6 +969,60 @@
       printer->Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
     }
   }
+
+  void ToProtoScreens(pb::Badging* out_badging, int32_t target_sdk) const {
+    auto supports_screen = out_badging->mutable_supports_screen();
+    if (IsSmallScreenSupported(target_sdk)) {
+      supports_screen->add_screens(pb::SupportsScreen_ScreenType_SMALL);
+    }
+    if (normal_screen != 0) {
+      supports_screen->add_screens(pb::SupportsScreen_ScreenType_NORMAL);
+    }
+    if (IsLargeScreenSupported(target_sdk)) {
+      supports_screen->add_screens(pb::SupportsScreen_ScreenType_LARGE);
+    }
+    if (IsXLargeScreenSupported(target_sdk)) {
+      supports_screen->add_screens(pb::SupportsScreen_ScreenType_XLARGE);
+    }
+    supports_screen->set_supports_any_densities(IsAnyDensitySupported(target_sdk));
+    supports_screen->set_requires_smallest_width_dp(requires_smallest_width_dp);
+    supports_screen->set_compatible_width_limit_dp(compatible_width_limit_dp);
+    supports_screen->set_largest_width_limit_dp(largest_width_limit_dp);
+  }
+
+ private:
+  // Determine default values for any unspecified screen sizes,
+  // based on the target SDK of the package.  As of 4 (donut)
+  // the screen size support was introduced, so all default to
+  // enabled.
+  bool IsSmallScreenSupported(int32_t target_sdk) const {
+    if (small_screen > 0) {
+      return target_sdk >= SDK_DONUT;
+    }
+    return small_screen != 0;
+  }
+
+  bool IsLargeScreenSupported(int32_t target_sdk) const {
+    if (large_screen > 0) {
+      return target_sdk >= SDK_DONUT;
+    }
+    return large_screen != 0;
+  }
+
+  bool IsXLargeScreenSupported(int32_t target_sdk) const {
+    if (xlarge_screen > 0) {
+      return target_sdk >= SDK_GINGERBREAD;
+    }
+    return xlarge_screen != 0;
+  }
+
+  bool IsAnyDensitySupported(int32_t target_sdk) const {
+    if (any_density > 0) {
+      return target_sdk >= SDK_DONUT || requires_smallest_width_dp > 0 ||
+             compatible_width_limit_dp > 0;
+    }
+    return any_density != 0;
+  }
 };
 
 /** Represents <feature-group> elements. **/
@@ -847,6 +1053,18 @@
     }
   }
 
+  virtual void GroupToProto(pb::Badging* out_badging) {
+    auto feature_group = out_badging->add_feature_groups();
+    feature_group->set_label(label);
+    feature_group->set_open_gles_version(open_gles_version);
+    for (auto& feature : features_) {
+      auto out_feature = feature_group->add_features();
+      out_feature->set_name(feature.first);
+      out_feature->set_required(feature.second.required);
+      out_feature->set_version(feature.second.version);
+    }
+  }
+
   /** Adds a feature to the feature group. */
   void AddFeature(const std::string& name, bool required = true, int32_t version = -1) {
     features_.insert(std::make_pair(name, Feature{ required, version }));
@@ -936,6 +1154,23 @@
     }
   }
 
+  virtual void GroupToProto(pb::Badging* out_badging) override {
+    FeatureGroup::GroupToProto(out_badging);
+    auto feature_group =
+        out_badging->mutable_feature_groups(out_badging->feature_groups_size() - 1);
+    for (auto& feature : implied_features_) {
+      if (features_.find(feature.first) == features_.end()) {
+        auto out_feature = feature_group->add_features();
+        out_feature->set_name(feature.first);
+        auto implied_data = out_feature->mutable_implied_data();
+        implied_data->set_from_sdk_23_permission(feature.second.implied_from_sdk_k23);
+        for (auto& reason : feature.second.reasons) {
+          implied_data->add_reasons(reason);
+        }
+      }
+    }
+  }
+
   /** Returns true if the feature group has the given feature. */
   bool HasFeature(const std::string& name) override {
     return FeatureGroup::HasFeature(name)
@@ -1165,6 +1400,27 @@
       printer->Print(StringPrintf(" reason='%s'\n", impliedReason.data()));
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    if (!name.empty()) {
+      auto permission = out_badging->add_uses_permissions();
+      permission->set_name(name);
+      if (maxSdkVersion > 0) {
+        permission->set_max_sdk_version(maxSdkVersion);
+      }
+      if ((usesPermissionFlags & kNeverForLocation) != 0) {
+        permission->mutable_permission_flags()->set_never_for_location(true);
+      }
+      for (auto& requiredFeature : requiredFeatures) {
+        permission->add_required_features(requiredFeature);
+      }
+      for (auto& requiredNotFeature : requiredNotFeatures) {
+        permission->add_required_not_features(requiredNotFeature);
+      }
+      permission->set_required(required != 0);
+      permission->set_implied(implied);
+    }
+  }
 };
 
 /** Represents <required-feature> elements. **/
@@ -1225,6 +1481,17 @@
       printer->Print("\n");
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    if (name) {
+      auto permission = out_badging->add_uses_permissions();
+      permission->set_sdk23_and_above(true);
+      permission->set_name(*name);
+      if (maxSdkVersion) {
+        permission->set_max_sdk_version(*maxSdkVersion);
+      }
+    }
+  }
 };
 
 /** Represents <permission> elements. These elements are only printing when dumping permissions. **/
@@ -1242,6 +1509,12 @@
       printer->Print(StringPrintf("permission: %s\n", name.data()));
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    if (!name.empty()) {
+      out_badging->add_permissions()->set_name(name);
+    }
+  }
 };
 
 /** Represents <activity> elements. **/
@@ -1322,6 +1595,22 @@
                                   icon.data(), banner.data()));
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    if (has_main_action && has_launcher_category) {
+      auto activity = out_badging->mutable_launchable_activity();
+      activity->set_name(name);
+      activity->set_label(android::ResTable::normalizeForOutput(label.data()));
+      activity->set_icon(icon);
+    }
+    if (has_leanback_launcher_category) {
+      auto activity = out_badging->mutable_leanback_launchable_activity();
+      activity->set_name(name);
+      activity->set_label(android::ResTable::normalizeForOutput(label.data()));
+      activity->set_icon(icon);
+      activity->set_banner(banner);
+    }
+  }
 };
 
 /** Represents <intent-filter> elements. */
@@ -1422,6 +1711,14 @@
                                  (required == 0) ? "-not-required" : "", name.data()));
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    if (!name.empty()) {
+      auto uses_library = out_badging->add_uses_libraries();
+      uses_library->set_name(name);
+      uses_library->set_required(required != 0);
+    }
+  }
 };
 
 /** Represents <static-library> elements. **/
@@ -1446,6 +1743,13 @@
       "static-library: name='%s' version='%d' versionMajor='%d'\n",
       name.data(), version, versionMajor));
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    auto static_library = out_badging->mutable_static_library();
+    static_library->set_name(name);
+    static_library->set_version(version);
+    static_library->set_version_major(versionMajor);
+  }
 };
 
 /** Represents <uses-static-library> elements. **/
@@ -1486,6 +1790,16 @@
     }
     printer->Print("\n");
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    auto uses_static_library = out_badging->add_uses_static_libraries();
+    uses_static_library->set_name(name);
+    uses_static_library->set_version(version);
+    uses_static_library->set_version_major(versionMajor);
+    for (auto& cert : certDigests) {
+      uses_static_library->add_certificates(cert);
+    }
+  }
 };
 
 /** Represents <sdk-library> elements. **/
@@ -1507,6 +1821,12 @@
     printer->Print(
         StringPrintf("sdk-library: name='%s' versionMajor='%d'\n", name.data(), versionMajor));
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    auto sdk_library = out_badging->mutable_sdk_library();
+    sdk_library->set_name(name);
+    sdk_library->set_version_major(versionMajor);
+  }
 };
 
 /** Represents <uses-sdk-library> elements. **/
@@ -1544,6 +1864,15 @@
     }
     printer->Print("\n");
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    auto uses_sdk_library = out_badging->add_uses_sdk_libraries();
+    uses_sdk_library->set_name(name);
+    uses_sdk_library->set_version_major(versionMajor);
+    for (auto& cert : certDigests) {
+      uses_sdk_library->add_certificates(cert);
+    }
+  }
 };
 
 /** Represents <uses-native-library> elements. **/
@@ -1567,6 +1896,14 @@
                                  (required == 0) ? "-not-required" : "", name.data()));
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    if (!name.empty()) {
+      auto uses_native_library = out_badging->add_uses_native_libraries();
+      uses_native_library->set_name(name);
+      uses_native_library->set_required(required != 0);
+    }
+  }
 };
 
 /**
@@ -1607,6 +1944,24 @@
       printer->Print("\n");
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    if (!name.empty()) {
+      auto metadata = out_badging->add_metadata();
+      metadata->set_name(name);
+      if (!value.empty()) {
+        metadata->set_value_string(value);
+      } else if (value_int) {
+        metadata->set_value_int(*value_int);
+      } else {
+        if (!resource.empty()) {
+          metadata->set_resource_string(resource);
+        } else if (resource_int) {
+          metadata->set_resource_int(*resource_int);
+        }
+      }
+    }
+  }
 };
 
 /**
@@ -1736,6 +2091,13 @@
       printer->Print("\n");
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    auto supports_input = out_badging->mutable_supports_input();
+    for (auto& input : inputs) {
+      supports_input->add_inputs(input);
+    }
+  }
 };
 
 /** Represents <input-type> elements. **/
@@ -1769,6 +2131,12 @@
       printer->Print(StringPrintf("original-package:'%s'\n", name->data()));
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    if (name) {
+      out_badging->mutable_package()->set_original_package(*name);
+    }
+  }
 };
 
 
@@ -1807,6 +2175,21 @@
     }
     printer->Print("\n");
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    auto overlay = out_badging->mutable_overlay();
+    if (target_package) {
+      overlay->set_target_package(*target_package);
+    }
+    overlay->set_priority(priority);
+    overlay->set_static_(is_static);
+    if (required_property_name) {
+      overlay->set_required_property_name(*required_property_name);
+    }
+    if (required_property_value) {
+      overlay->set_required_property_value(*required_property_value);
+    }
+  }
 };
 
 /** * Represents <package-verifier> elements. **/
@@ -1827,6 +2210,14 @@
                                  name->data(), public_key->data()));
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    auto package_verifier = out_badging->mutable_package_verifier();
+    if (name && public_key) {
+      package_verifier->set_name(*name);
+      package_verifier->set_public_key(*public_key);
+    }
+  }
 };
 
 /** Represents <uses-package> elements. **/
@@ -1875,6 +2266,21 @@
       }
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    if (name) {
+      auto uses_package = out_badging->add_uses_packages();
+      uses_package->set_name(*name);
+      if (packageType) {
+        uses_package->set_package_type(*packageType);
+        uses_package->set_version(version);
+        uses_package->set_version_major(versionMajor);
+        for (auto& cert : certDigests) {
+          uses_package->add_certificates(cert);
+        }
+      }
+    }
+  }
 };
 
 /** Represents <additional-certificate> elements. **/
@@ -1907,6 +2313,14 @@
     size = GetAttributeInteger(FindAttribute(element, SCREEN_SIZE_ATTR));
     density = GetAttributeInteger(FindAttribute(element, SCREEN_DENSITY_ATTR));
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    if (size && density) {
+      auto screen = out_badging->mutable_compatible_screens()->add_screens();
+      screen->set_density(*density);
+      screen->set_size(*size);
+    }
+  }
 };
 
 /**
@@ -1952,6 +2366,12 @@
       printer->Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
     }
   }
+
+  void ToProto(pb::Badging* out_badging) override {
+    if (name) {
+      out_badging->mutable_supports_gl_texture()->add_name(*name);
+    }
+  }
 };
 
 /** Represents <property> elements. **/
@@ -1987,27 +2407,22 @@
     }
     printer->Print("\n");
   }
-};
 
-class Architectures {
- public:
-  std::set<std::string> architectures;
-  std::set<std::string> alt_architectures;
-
-  void Print(text::Printer* printer) {
-    if (!architectures.empty()) {
-      printer->Print("native-code:");
-      for (auto& arch : architectures) {
-        printer->Print(StringPrintf(" '%s'", arch.data()));
+  void ToProto(pb::Badging* out_badging) override {
+    if (!name.empty()) {
+      auto property = out_badging->add_properties();
+      property->set_name(name);
+      if (!value.empty()) {
+        property->set_value_string(value);
+      } else if (value_int) {
+        property->set_value_int(*value_int);
+      } else {
+        if (!resource.empty()) {
+          property->set_resource_string(resource);
+        } else if (resource_int) {
+          property->set_resource_int(*resource_int);
+        }
       }
-      printer->Print("\n");
-    }
-    if (!alt_architectures.empty()) {
-      printer->Print("alt-native-code:");
-      for (auto& arch : alt_architectures) {
-        printer->Print(StringPrintf(" '%s'", arch.data()));
-      }
-      printer->Print("\n");
     }
   }
 };
@@ -2020,6 +2435,14 @@
   }
 }
 
+/** Recursively serializes extracted badging elements to proto. */
+static void ToProto(ManifestExtractor::Element* el, pb::Badging* out_badging) {
+  el->ToProto(out_badging);
+  for (auto& child : el->children()) {
+    ToProto(child.get(), out_badging);
+  }
+}
+
 bool ManifestExtractor::Extract(IDiagnostics* diag) {
   // Load the manifest
   doc_ = apk_->LoadXml("AndroidManifest.xml", diag);
@@ -2198,7 +2621,7 @@
     if (ElementCast<Action>(el)) {
       auto action = ElementCast<Action>(el);
       if (!action->component.empty()) {
-        components_.insert(action->component);
+        components_.discovered_components.insert(action->component);
         return;
       }
     }
@@ -2206,7 +2629,7 @@
     if (ElementCast<Category>(el)) {
       auto category = ElementCast<Category>(el);
       if (!category->component.empty()) {
-        components_.insert(category->component);
+        components_.discovered_components.insert(category->component);
         return;
       }
     }
@@ -2256,7 +2679,7 @@
                              if (child->name == "aid-group") {
                                auto category = FindAttribute(child, CATEGORY_ATTR);
                                if (category && category->value == "payment") {
-                                 this->components_.insert("payment");
+                                 this->components_.discovered_components.insert("payment");
                                  return;
                                }
                              }
@@ -2272,7 +2695,7 @@
   FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
     if (auto activity = ElementCast<Activity>(el)) {
       if (!activity->has_component_) {
-        other_activities_ = true;
+        components_.other_activities = true;
         return true;
       }
     }
@@ -2282,7 +2705,7 @@
   FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
     if (auto receiver = ElementCast<Receiver>(el)) {
       if (!receiver->has_component) {
-        other_receivers_ = true;
+        components_.other_receivers = true;
         return true;
       }
     }
@@ -2292,7 +2715,7 @@
   FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
     if (auto service = ElementCast<Service>(el)) {
       if (!service->has_component) {
-        other_services_ = true;
+        components_.other_services = true;
         return true;
       }
     }
@@ -2358,16 +2781,16 @@
     }
 
     if (arch != architectures_from_apk.end()) {
-      architectures_->architectures.insert(*arch);
+      architectures_.architectures.insert(*arch);
       architectures_from_apk.erase(arch);
       output_alt_native_code = true;
     }
   }
   for (auto& arch : architectures_from_apk) {
     if (output_alt_native_code) {
-      architectures_->alt_architectures.insert(arch);
+      architectures_.alt_architectures.insert(arch);
     } else {
-      architectures_->architectures.insert(arch);
+      architectures_.architectures.insert(arch);
     }
   }
   return true;
@@ -2385,43 +2808,7 @@
   for (auto& feature_group : feature_groups_) {
     feature_group->PrintGroup(printer);
   }
-  // Print the components types if they are present
-  auto& components = components_;
-  auto PrintComponent = [&components, &printer](const std::string& component) -> void {
-    if (components.find(component) != components.end()) {
-      printer->Print(StringPrintf("provides-component:'%s'\n", component.data()));
-    }
-  };
-
-  PrintComponent("app-widget");
-  PrintComponent("device-admin");
-  PrintComponent("ime");
-  PrintComponent("wallpaper");
-  PrintComponent("accessibility");
-  PrintComponent("print-service");
-  PrintComponent("payment");
-  PrintComponent("search");
-  PrintComponent("document-provider");
-  PrintComponent("launcher");
-  PrintComponent("notification-listener");
-  PrintComponent("dream");
-  PrintComponent("camera");
-  PrintComponent("camera-secure");
-
-  // Print presence of main activity
-  if (components.find("main") != components.end()) {
-    printer->Print("main\n");
-  }
-
-  if (other_activities_) {
-    printer->Print("other-activities\n");
-  }
-  if (other_receivers_) {
-    printer->Print("other-receivers\n");
-  }
-  if (other_services_) {
-    printer->Print("other-services\n");
-  }
+  components_.Print(printer);
   supports_screen_->PrintScreens(printer, target_sdk_);
 
   // Print all the unique locales of the apk
@@ -2442,7 +2829,31 @@
   }
   printer->Print("\n");
 
-  architectures_->Print(printer);
+  architectures_.Print(printer);
+  return true;
+}
+
+bool ManifestExtractor::DumpProto(pb::Badging* out_badging) {
+  ToProto(root_element_.get(), out_badging);
+  for (auto& implied_permission : implied_permissions_) {
+    implied_permission->ToProto(out_badging);
+  }
+  for (auto& feature_group : feature_groups_) {
+    feature_group->GroupToProto(out_badging);
+  }
+  components_.ToProto(out_badging);
+  supports_screen_->ToProtoScreens(out_badging, target_sdk_);
+
+  for (auto& config : locales_) {
+    if (!config.first.empty()) {
+      out_badging->add_locales(config.first);
+    }
+  }
+  for (auto& config : densities_) {
+    out_badging->add_densities(config.first);
+  }
+
+  architectures_.ToProto(out_badging);
   return true;
 }
 
@@ -2581,14 +2992,23 @@
   return element;
 }
 
-
 int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
                  IDiagnostics* diag) {
   ManifestExtractor extractor(apk, options);
   if (!extractor.Extract(diag)) {
-    return 0;
+    return 1;
   }
   return extractor.Dump(printer) ? 0 : 1;
 }
 
+int DumpBadgingProto(LoadedApk* apk, pb::Badging* out_badging, IDiagnostics* diag) {
+  DumpManifestOptions options{/* include_meta_data= */ true,
+                              /* only_permissions= */ false};
+  ManifestExtractor extractor(apk, options);
+  if (!extractor.Extract(diag)) {
+    return 1;
+  }
+  return extractor.DumpProto(out_badging) ? 0 : 1;
+}
+
 } // namespace aapt