Split ManifestExtractor to Extract and Print methods.
Bug: b/228950123
Test: Dump_test.cpp
Change-Id: I040224f4997d2904e899211898e59e9fc4d58f82
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 2c833e7..64a9441 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -17,17 +17,19 @@
#include "DumpManifest.h"
#include <algorithm>
+#include <memory>
+#include <set>
+#include <vector>
#include "LoadedApk.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
+#include "androidfw/ConfigDescription.h"
#include "io/File.h"
#include "io/FileStream.h"
#include "process/IResourceTableConsumer.h"
#include "xml/XmlDom.h"
-#include "androidfw/ConfigDescription.h"
-
using ::android::base::StringPrintf;
using ::android::ConfigDescription;
@@ -113,6 +115,9 @@
}
class CommonFeatureGroup;
+class Architectures;
+class SupportsScreen;
+class FeatureGroup;
class ManifestExtractor {
public:
@@ -338,7 +343,8 @@
return config;
}
- bool Dump(text::Printer* printer, IDiagnostics* diag);
+ bool Extract(IDiagnostics* diag);
+ bool Dump(text::Printer* printer);
/** Recursively visit the xml element tree and return a processed badging element tree. */
std::unique_ptr<Element> Visit(xml::Element* element);
@@ -354,7 +360,7 @@
* Retrieves the default feature group that features are added into when <uses-feature>
* are not in a <feature-group> element.
**/
- CommonFeatureGroup* GetCommonFeatureGroup() {
+ CommonFeatureGroup* common_feature_group() {
return commonFeatureGroup_.get();
}
@@ -387,11 +393,22 @@
DumpManifestOptions& options_;
private:
+ std::unique_ptr<xml::XmlResource> doc_;
std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
std::map<std::string, ConfigDescription> locales_;
std::map<uint16_t, ConfigDescription> densities_;
std::vector<Element*> parent_stack_;
int32_t target_sdk_ = 0;
+
+ 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>();
+ const SupportsScreen* supports_screen_;
};
template<typename T> T* ElementCast(ManifestExtractor::Element* element);
@@ -427,6 +444,7 @@
class Manifest : public ManifestExtractor::Element {
public:
Manifest() = default;
+ bool only_package_name;
std::string package;
int32_t versionCode;
std::string versionName;
@@ -463,6 +481,14 @@
}
void Print(text::Printer* printer) override {
+ if (only_package_name) {
+ printer->Println(StringPrintf("package: %s", package.data()));
+ } else {
+ PrintFull(printer);
+ }
+ }
+
+ void PrintFull(text::Printer* printer) {
printer->Print(StringPrintf("package: name='%s' ", package.data()));
printer->Print(StringPrintf("versionCode='%s' ",
(versionCode > 0) ? std::to_string(versionCode).data() : ""));
@@ -733,7 +759,7 @@
}
}
- void PrintScreens(text::Printer* printer, int32_t target_sdk) {
+ 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;
@@ -1050,7 +1076,7 @@
// common feature group
FeatureGroup* feature_group = ElementCast<FeatureGroup>(extractor()->parent_stack()[0]);
if (!feature_group) {
- feature_group = extractor()->GetCommonFeatureGroup();
+ feature_group = extractor()->common_feature_group();
} else {
// All features in side of <feature-group> elements are required.
required = true;
@@ -1068,12 +1094,14 @@
class UsesPermission : public ManifestExtractor::Element {
public:
UsesPermission() = default;
+ bool implied;
std::string name;
std::vector<std::string> requiredFeatures;
std::vector<std::string> requiredNotFeatures;
int32_t required = true;
int32_t maxSdkVersion = -1;
int32_t usesPermissionFlags = 0;
+ std::string impliedReason;
void Extract(xml::Element* element) override {
name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
@@ -1094,7 +1122,7 @@
FindAttribute(element, USES_PERMISSION_FLAGS_ATTR), 0);
if (!name.empty()) {
- CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ CommonFeatureGroup* common = extractor()->common_feature_group();
common->addImpliedFeaturesForPermission(extractor()->target_sdk(), name, false);
}
}
@@ -1126,17 +1154,16 @@
printer->Print("\n");
}
}
- }
-
- void PrintImplied(text::Printer* printer, const std::string& reason) {
- printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
- if (maxSdkVersion >= 0) {
- printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+ if (implied) {
+ printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
+ if (maxSdkVersion >= 0) {
+ printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+ }
+ if ((usesPermissionFlags & kNeverForLocation) != 0) {
+ printer->Print(StringPrintf(" usesPermissionFlags='neverForLocation'"));
+ }
+ printer->Print(StringPrintf(" reason='%s'\n", impliedReason.data()));
}
- if ((usesPermissionFlags & kNeverForLocation) != 0) {
- printer->Print(StringPrintf(" usesPermissionFlags='neverForLocation'"));
- }
- printer->Print(StringPrintf(" reason='%s'\n", reason.data()));
}
};
@@ -1184,7 +1211,7 @@
maxSdkVersion = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
if (name) {
- CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ CommonFeatureGroup* common = extractor()->common_feature_group();
common->addImpliedFeaturesForPermission(extractor()->target_sdk(), *name, true);
}
}
@@ -1256,7 +1283,7 @@
auto orientation = GetAttributeInteger(FindAttribute(element, SCREEN_ORIENTATION_ATTR));
if (orientation) {
- CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ CommonFeatureGroup* common = extractor()->common_feature_group();
int orien = *orientation;
if (orien == 0 || orien == 6 || orien == 8) {
// Requests landscape, sensorLandscape, or reverseLandscape.
@@ -1962,6 +1989,29 @@
}
};
+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");
+ }
+ }
+};
+
/** Recursively prints the extracted badging element. */
static void Print(ManifestExtractor::Element* el, text::Printer* printer) {
el->Print(printer);
@@ -1970,15 +2020,15 @@
}
}
-bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
+bool ManifestExtractor::Extract(IDiagnostics* diag) {
// Load the manifest
- std::unique_ptr<xml::XmlResource> doc = apk_->LoadXml("AndroidManifest.xml", diag);
- if (doc == nullptr) {
+ doc_ = apk_->LoadXml("AndroidManifest.xml", diag);
+ if (doc_ == nullptr) {
diag->Error(DiagMessage() << "failed to find AndroidManifest.xml");
return false;
}
- xml::Element* element = doc->root.get();
+ xml::Element* element = doc_->root.get();
if (element->name != "manifest") {
diag->Error(DiagMessage() << "manifest does not start with <manifest> tag");
return false;
@@ -1987,10 +2037,11 @@
// Print only the <uses-permission>, <uses-permission-sdk23>, and <permission> elements if
// printing only permission elements is requested
if (options_.only_permissions) {
- std::unique_ptr<ManifestExtractor::Element> manifest_element =
- ManifestExtractor::Element::Inflate(this, element);
+ root_element_ = ManifestExtractor::Element::Inflate(this, element);
- if (auto manifest = ElementCast<Manifest>(manifest_element.get())) {
+ if (auto manifest = ElementCast<Manifest>(root_element_.get())) {
+ manifest->only_package_name = true;
+
for (xml::Element* child : element->GetChildElements()) {
if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
|| child->name == "permission") {
@@ -1999,15 +2050,8 @@
manifest->AddChild(permission_element);
}
}
-
- printer->Print(StringPrintf("package: %s\n", manifest->package.data()));
- ForEachChild(manifest, [&printer](ManifestExtractor::Element* el) -> void {
- el->Print(printer);
- });
-
return true;
}
-
return false;
}
@@ -2041,27 +2085,24 @@
}
// Extract badging information
- auto root = Visit(element);
+ root_element_ = Visit(element);
// Filter out all "uses-sdk" tags besides the very last tag. The android runtime only uses the
// attribute values from the last defined tag.
std::vector<UsesSdkBadging*> filtered_uses_sdk_tags;
- for (const auto& child : root->children()) {
+ for (const auto& child : root_element_->children()) {
if (auto uses_sdk = ElementCast<UsesSdkBadging>(child.get())) {
filtered_uses_sdk_tags.emplace_back(uses_sdk);
}
}
if (filtered_uses_sdk_tags.size() >= 2U) {
filtered_uses_sdk_tags.pop_back();
- root->Filter([&](const ManifestExtractor::Element* e) {
+ root_element_->Filter([&](const ManifestExtractor::Element* e) {
return std::find(filtered_uses_sdk_tags.begin(), filtered_uses_sdk_tags.end(), e) !=
filtered_uses_sdk_tags.end();
});
}
- // Print the elements in order seen
- Print(root.get(), printer);
-
/** Recursively checks the extracted elements for the specified permission. **/
auto FindPermission = [&](ManifestExtractor::Element* root,
const std::string& name) -> ManifestExtractor::Element* {
@@ -2073,30 +2114,30 @@
});
};
- auto PrintPermission = [&printer](const std::string& name, const std::string& reason,
- int32_t max_sdk_version) -> void {
+ auto AddImpliedPermission = [&](const std::string& name, const std::string& reason,
+ int32_t max_sdk_version) -> void {
auto permission = util::make_unique<UsesPermission>();
permission->name = name;
permission->maxSdkVersion = max_sdk_version;
- permission->Print(printer);
- permission->PrintImplied(printer, reason);
+ permission->implied = true;
+ permission->impliedReason = reason;
+ implied_permissions_.push_back(std::move(permission));
};
// Implied permissions
// Pre-1.6 implicitly granted permission compatibility logic
- CommonFeatureGroup* common_feature_group = GetCommonFeatureGroup();
bool insert_write_external = false;
auto write_external_permission = ElementCast<UsesPermission>(
- FindPermission(root.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
+ FindPermission(root_element_.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
if (target_sdk() < SDK_DONUT) {
if (!write_external_permission) {
- PrintPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
+ AddImpliedPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
insert_write_external = true;
}
- if (!FindPermission(root.get(), "android.permission.READ_PHONE_STATE")) {
- PrintPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
+ if (!FindPermission(root_element_.get(), "android.permission.READ_PHONE_STATE")) {
+ AddImpliedPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
}
}
@@ -2104,62 +2145,60 @@
// force them to always take READ_EXTERNAL_STORAGE as well. We always
// do this (regardless of target API version) because we can't have
// an app with write permission but not read permission.
- auto read_external = FindPermission(root.get(), "android.permission.READ_EXTERNAL_STORAGE");
+ auto read_external =
+ FindPermission(root_element_.get(), "android.permission.READ_EXTERNAL_STORAGE");
if (!read_external && (insert_write_external || write_external_permission)) {
- PrintPermission("android.permission.READ_EXTERNAL_STORAGE",
- "requested WRITE_EXTERNAL_STORAGE",
- (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
+ AddImpliedPermission(
+ "android.permission.READ_EXTERNAL_STORAGE", "requested WRITE_EXTERNAL_STORAGE",
+ (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
}
// Pre-JellyBean call log permission compatibility.
if (target_sdk() < SDK_JELLY_BEAN) {
- if (!FindPermission(root.get(), "android.permission.READ_CALL_LOG")
- && FindPermission(root.get(), "android.permission.READ_CONTACTS")) {
- PrintPermission("android.permission.READ_CALL_LOG",
- "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
+ if (!FindPermission(root_element_.get(), "android.permission.READ_CALL_LOG") &&
+ FindPermission(root_element_.get(), "android.permission.READ_CONTACTS")) {
+ AddImpliedPermission("android.permission.READ_CALL_LOG",
+ "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
}
- if (!FindPermission(root.get(), "android.permission.WRITE_CALL_LOG")
- && FindPermission(root.get(), "android.permission.WRITE_CONTACTS")) {
- PrintPermission("android.permission.WRITE_CALL_LOG",
- "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
+ if (!FindPermission(root_element_.get(), "android.permission.WRITE_CALL_LOG") &&
+ FindPermission(root_element_.get(), "android.permission.WRITE_CONTACTS")) {
+ AddImpliedPermission("android.permission.WRITE_CALL_LOG",
+ "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
}
}
// If the app hasn't declared the touchscreen as a feature requirement (either
// directly or implied, required or not), then the faketouch feature is implied.
- if (!common_feature_group->HasFeature("android.hardware.touchscreen")) {
- common_feature_group->addImpliedFeature("android.hardware.faketouch",
- "default feature for all apps", false);
+ if (!common_feature_group()->HasFeature("android.hardware.touchscreen")) {
+ common_feature_group()->addImpliedFeature("android.hardware.faketouch",
+ "default feature for all apps", false);
}
// Only print the common feature group if no feature group is defined
std::vector<FeatureGroup*> feature_groups;
- ForEachChild(root.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
+ ForEachChild(root_element_.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
if (auto feature_group = ElementCast<FeatureGroup>(el)) {
feature_groups.push_back(feature_group);
}
});
if (feature_groups.empty()) {
- common_feature_group->PrintGroup(printer);
+ feature_groups_.push_back(common_feature_group());
} else {
// Merge the common feature group into the feature group
for (auto& feature_group : feature_groups) {
- feature_group->open_gles_version = std::max(feature_group->open_gles_version,
- common_feature_group->open_gles_version);
- feature_group->Merge(common_feature_group);
- feature_group->PrintGroup(printer);
+ feature_group->Merge(common_feature_group());
+ feature_groups_.push_back(feature_group);
}
};
// Collect the component types of the application
- std::set<std::string> components;
- ForEachChild(root.get(), [&components](ManifestExtractor::Element* el) -> void {
+ ForEachChild(root_element_.get(), [&](ManifestExtractor::Element* el) -> void {
if (ElementCast<Action>(el)) {
auto action = ElementCast<Action>(el);
if (!action->component.empty()) {
- components.insert(action->component);
+ components_.insert(action->component);
return;
}
}
@@ -2167,15 +2206,14 @@
if (ElementCast<Category>(el)) {
auto category = ElementCast<Category>(el);
if (!category->component.empty()) {
- components.insert(category->component);
+ components_.insert(category->component);
return;
}
}
});
// Check for the payment component
- auto apk = apk_;
- ForEachChild(root.get(), [&apk, &components, &diag](ManifestExtractor::Element* el) -> void {
+ ForEachChild(root_element_.get(), [this, &diag](ManifestExtractor::Element* el) -> void {
if (auto service = ElementCast<Service>(el)) {
auto host_apdu_action = ElementCast<Action>(FindElement(service,
[&](ManifestExtractor::Element* el) -> bool {
@@ -2193,44 +2231,162 @@
return false;
}));
- ForEachChild(service, [&apk, &components, &diag, &host_apdu_action,
- &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
- if (auto meta_data = ElementCast<MetaData>(el)) {
- if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" && host_apdu_action)
- || (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service"
- && offhost_apdu_action)) {
+ ForEachChild(service,
+ [this, &diag, &host_apdu_action,
+ &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
+ if (auto meta_data = ElementCast<MetaData>(el)) {
+ if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" &&
+ host_apdu_action) ||
+ (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service" &&
+ offhost_apdu_action)) {
+ // Attempt to load the resource file
+ if (!meta_data->resource.empty()) {
+ return;
+ }
+ auto resource = this->apk_->LoadXml(meta_data->resource, diag);
+ if (!resource) {
+ return;
+ }
- // Attempt to load the resource file
- if (!meta_data->resource.empty()) {
- return;
- }
- auto resource = apk->LoadXml(meta_data->resource, diag);
- if (!resource) {
- return;
- }
-
- // Look for the payment category on an <aid-group> element
- auto& root = resource.get()->root;
- if ((host_apdu_action && root->name == "host-apdu-service")
- || (offhost_apdu_action && root->name == "offhost-apdu-service")) {
-
- for (auto& child : root->GetChildElements()) {
- if (child->name == "aid-group") {
- auto category = FindAttribute(child, CATEGORY_ATTR);
- if (category && category->value == "payment") {
- components.insert("payment");
- return;
- }
- }
- }
- }
- }
- }
- });
+ // Look for the payment category on an <aid-group> element
+ auto& root = resource.get()->root;
+ if ((host_apdu_action && root->name == "host-apdu-service") ||
+ (offhost_apdu_action && root->name == "offhost-apdu-service")) {
+ for (auto& child : root->GetChildElements()) {
+ if (child->name == "aid-group") {
+ auto category = FindAttribute(child, CATEGORY_ATTR);
+ if (category && category->value == "payment") {
+ this->components_.insert("payment");
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ });
}
});
+ // Print presence of activities, receivers, and services with no special components
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
+ if (auto activity = ElementCast<Activity>(el)) {
+ if (!activity->has_component_) {
+ other_activities_ = true;
+ return true;
+ }
+ }
+ return false;
+ });
+
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
+ if (auto receiver = ElementCast<Receiver>(el)) {
+ if (!receiver->has_component) {
+ other_receivers_ = true;
+ return true;
+ }
+ }
+ return false;
+ });
+
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
+ if (auto service = ElementCast<Service>(el)) {
+ if (!service->has_component) {
+ other_services_ = true;
+ return true;
+ }
+ }
+ return false;
+ });
+
+ // Gather the supported screens
+ const static SupportsScreen default_screens{};
+ SupportsScreen* screen = ElementCast<SupportsScreen>(
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
+ return ElementCast<SupportsScreen>(el) != nullptr;
+ }));
+ supports_screen_ = screen ? screen : &default_screens;
+
+ // Gather the supported architectures_ of the app
+ std::set<std::string> architectures_from_apk;
+ auto it = apk_->GetFileCollection()->Iterator();
+ while (it->HasNext()) {
+ auto file_path = it->Next()->GetSource().path;
+ size_t pos = file_path.find("lib/");
+ if (pos != std::string::npos) {
+ file_path = file_path.substr(pos + 4);
+ pos = file_path.find('/');
+ if (pos != std::string::npos) {
+ file_path = file_path.substr(0, pos);
+ }
+
+ architectures_from_apk.insert(file_path);
+ }
+ }
+
+ // Determine if the application has multiArch supports
+ auto has_multi_arch =
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
+ if (auto application = ElementCast<Application>(el)) {
+ return application->has_multi_arch;
+ }
+ return false;
+ });
+
+ bool output_alt_native_code = false;
+ // A multiArch package is one that contains 64-bit and
+ // 32-bit versions of native code and expects 3rd-party
+ // apps to load these native code libraries. Since most
+ // 64-bit systems also support 32-bit apps, the apps
+ // loading this multiArch package's code may be either
+ if (has_multi_arch) {
+ // If this is a multiArch package, report the 64-bit
+ // version only. Then as a separate entry, report the
+ // rest.
+ //
+ // If we report the 32-bit architecture, this APK will
+ // be installed on a 32-bit device, causing a large waste
+ // of bandwidth and disk space. This assumes that
+ // the developer of the multiArch package has also
+ // made a version that is 32-bit only.
+ const std::string kIntel64 = "x86_64";
+ const std::string kArm64 = "arm64-v8a";
+
+ auto arch = architectures_from_apk.find(kIntel64);
+ if (arch == architectures_from_apk.end()) {
+ arch = architectures_from_apk.find(kArm64);
+ }
+
+ if (arch != architectures_from_apk.end()) {
+ 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);
+ } else {
+ architectures_->architectures.insert(arch);
+ }
+ }
+ return true;
+}
+
+bool ManifestExtractor::Dump(text::Printer* printer) {
+ Print(root_element_.get(), printer);
+ if (options_.only_permissions) {
+ return true;
+ }
+
+ for (auto& implied_permission : implied_permissions_) {
+ implied_permission->Print(printer);
+ }
+ 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()));
@@ -2257,50 +2413,16 @@
printer->Print("main\n");
}
- // Print presence of activities, recivers, and services with no special components
- FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
- if (auto activity = ElementCast<Activity>(el)) {
- if (!activity->has_component_) {
- printer->Print("other-activities\n");
- return true;
- }
- }
- return false;
- });
-
- FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
- if (auto receiver = ElementCast<Receiver>(el)) {
- if (!receiver->has_component) {
- printer->Print("other-receivers\n");
- return true;
- }
- }
- return false;
- });
-
- FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
- if (auto service = ElementCast<Service>(el)) {
- if (!service->has_component) {
- printer->Print("other-services\n");
- return true;
- }
- }
- return false;
- });
-
- // Print the supported screens
- SupportsScreen* screen = ElementCast<SupportsScreen>(FindElement(root.get(),
- [&](ManifestExtractor::Element* el) -> bool {
- return ElementCast<SupportsScreen>(el) != nullptr;
- }));
-
- if (screen) {
- screen->PrintScreens(printer, target_sdk_);
- } else {
- // Print the default supported screens
- SupportsScreen default_screens;
- default_screens.PrintScreens(printer, target_sdk_);
+ if (other_activities_) {
+ printer->Print("other-activities\n");
}
+ if (other_receivers_) {
+ printer->Print("other-receivers\n");
+ }
+ if (other_services_) {
+ printer->Print("other-services\n");
+ }
+ supports_screen_->PrintScreens(printer, target_sdk_);
// Print all the unique locales of the apk
printer->Print("locales:");
@@ -2320,75 +2442,7 @@
}
printer->Print("\n");
- // Print the supported architectures of the app
- std::set<std::string> architectures;
- auto it = apk_->GetFileCollection()->Iterator();
- while (it->HasNext()) {
- auto file_path = it->Next()->GetSource().path;
-
-
- size_t pos = file_path.find("lib/");
- if (pos != std::string::npos) {
- file_path = file_path.substr(pos + 4);
- pos = file_path.find('/');
- if (pos != std::string::npos) {
- file_path = file_path.substr(0, pos);
- }
-
- architectures.insert(file_path);
- }
- }
-
- // Determine if the application has multiArch supports
- auto has_multi_arch = FindElement(root.get(), [&](ManifestExtractor::Element* el) -> bool {
- if (auto application = ElementCast<Application>(el)) {
- return application->has_multi_arch;
- }
- return false;
- });
-
- bool output_alt_native_code = false;
- // A multiArch package is one that contains 64-bit and
- // 32-bit versions of native code and expects 3rd-party
- // apps to load these native code libraries. Since most
- // 64-bit systems also support 32-bit apps, the apps
- // loading this multiArch package's code may be either
- if (has_multi_arch) {
- // If this is a multiArch package, report the 64-bit
- // version only. Then as a separate entry, report the
- // rest.
- //
- // If we report the 32-bit architecture, this APK will
- // be installed on a 32-bit device, causing a large waste
- // of bandwidth and disk space. This assumes that
- // the developer of the multiArch package has also
- // made a version that is 32-bit only.
- const std::string kIntel64 = "x86_64";
- const std::string kArm64 = "arm64-v8a";
-
- auto arch = architectures.find(kIntel64);
- if (arch == architectures.end()) {
- arch = architectures.find(kArm64);
- }
-
- if (arch != architectures.end()) {
- printer->Print(StringPrintf("native-code: '%s'\n", arch->data()));
- architectures.erase(arch);
- output_alt_native_code = true;
- }
- }
-
- if (architectures.size() > 0) {
- if (output_alt_native_code) {
- printer->Print("alt-");
- }
- printer->Print("native-code:");
- for (auto& arch : architectures) {
- printer->Print(StringPrintf(" '%s'", arch.data()));
- }
- printer->Print("\n");
- }
-
+ architectures_->Print(printer);
return true;
}
@@ -2531,7 +2585,10 @@
int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
IDiagnostics* diag) {
ManifestExtractor extractor(apk, options);
- return extractor.Dump(printer, diag) ? 0 : 1;
+ if (!extractor.Extract(diag)) {
+ return 0;
+ }
+ return extractor.Dump(printer) ? 0 : 1;
}
} // namespace aapt