blob: 2c356d1491d5b10757ee2d69d9304e68fe09f42d [file] [log] [blame]
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "DumpManifest.h"
18
19#include "LoadedApk.h"
20#include "SdkConstants.h"
21#include "ValueVisitor.h"
22#include "io/File.h"
23#include "io/FileStream.h"
24#include "process/IResourceTableConsumer.h"
25#include "xml/XmlDom.h"
26
27using ::android::base::StringPrintf;
28
29namespace aapt {
30
31/**
32 * These are attribute resource constants for the platform, as found in android.R.attr.
33 */
34enum {
35 LABEL_ATTR = 0x01010001,
36 ICON_ATTR = 0x01010002,
37 NAME_ATTR = 0x01010003,
38 PERMISSION_ATTR = 0x01010006,
39 EXPORTED_ATTR = 0x01010010,
40 GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
41 RESOURCE_ATTR = 0x01010025,
42 DEBUGGABLE_ATTR = 0x0101000f,
43 VALUE_ATTR = 0x01010024,
44 VERSION_CODE_ATTR = 0x0101021b,
45 VERSION_NAME_ATTR = 0x0101021c,
46 SCREEN_ORIENTATION_ATTR = 0x0101001e,
47 MIN_SDK_VERSION_ATTR = 0x0101020c,
48 MAX_SDK_VERSION_ATTR = 0x01010271,
49 REQ_TOUCH_SCREEN_ATTR = 0x01010227,
50 REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
51 REQ_HARD_KEYBOARD_ATTR = 0x01010229,
52 REQ_NAVIGATION_ATTR = 0x0101022a,
53 REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
54 TARGET_SDK_VERSION_ATTR = 0x01010270,
55 TEST_ONLY_ATTR = 0x01010272,
56 ANY_DENSITY_ATTR = 0x0101026c,
57 GL_ES_VERSION_ATTR = 0x01010281,
58 SMALL_SCREEN_ATTR = 0x01010284,
59 NORMAL_SCREEN_ATTR = 0x01010285,
60 LARGE_SCREEN_ATTR = 0x01010286,
61 XLARGE_SCREEN_ATTR = 0x010102bf,
62 REQUIRED_ATTR = 0x0101028e,
63 INSTALL_LOCATION_ATTR = 0x010102b7,
64 SCREEN_SIZE_ATTR = 0x010102ca,
65 SCREEN_DENSITY_ATTR = 0x010102cb,
66 REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
67 COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
68 LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
69 PUBLIC_KEY_ATTR = 0x010103a6,
70 CATEGORY_ATTR = 0x010103e8,
71 BANNER_ATTR = 0x10103f2,
72 ISGAME_ATTR = 0x10103f4,
73 REQUIRED_FEATURE_ATTR = 0x1010557,
74 REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
75 COMPILE_SDK_VERSION_ATTR = 0x01010572,
76 COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573,
77};
78
79const std::string& kAndroidNamespace = "http://schemas.android.com/apk/res/android";
80
81/** Retrieves the attribute of the element with the specified attribute resource id. */
82static xml::Attribute* FindAttribute(xml::Element *el, uint32_t resd_id) {
83 for (auto& a : el->attributes) {
84 if (a.compiled_attribute && a.compiled_attribute.value().id) {
85 if (a.compiled_attribute.value().id.value() == resd_id) {
86 return std::move(&a);
87 }
88 }
89 }
90 return nullptr;
91}
92
93/** Retrieves the attribute of the element that has the specified namespace and attribute name. */
94static xml::Attribute* FindAttribute(xml::Element *el, const std::string &package,
95 const std::string &name) {
96 return el->FindAttribute(package, name);
97}
98
99class CommonFeatureGroup;
100
101class ManifestExtractor {
102 public:
103 struct Options {
104 /** Include meta information from <meta-data> elements in the output. */
105 bool include_meta_data = false;
106
107 /** Only output permission information. */
108 bool only_permissions = false;
109 };
110
111 explicit ManifestExtractor(LoadedApk* apk, ManifestExtractor::Options options)
112 : apk_(apk), options_(options) { }
113
114 class Element {
115 public:
116 Element() = default;
117 virtual ~Element() = default;
118
119 static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
120
121 /** Writes out the extracted contents of the element. */
122 virtual void Print(text::Printer& printer) { }
123
124 /** Adds an element to the list of children of the element. */
125 void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); }
126
127 /** Retrieves the list of children of the element. */
128 const std::vector<std::unique_ptr<Element>>& children() const {
129 return children_;
130 }
131
132 /** Retrieves the extracted xml element tag. */
133 const std::string tag() const {
134 return tag_;
135 }
136
137 protected:
138 ManifestExtractor* extractor() const {
139 return extractor_;
140 }
141
142 /** Retrieves and stores the information extracted from the xml element. */
143 virtual void Extract(xml::Element* el) { }
144
145 /*
146 * Retrieves a configuration value of the resource entry that best matches the specified
147 * configuration.
148 */
149 static Value* BestConfigValue(ResourceEntry* entry,
150 const ConfigDescription& match) {
151 if (!entry) {
152 return nullptr;
153 }
154
155 // Determine the config that best matches the desired config
156 ResourceConfigValue* best_value = nullptr;
157 for (auto& value : entry->values) {
158 if (!value->config.match(match)) {
159 continue;
160 }
161
162 if (best_value != nullptr) {
163 if (!value->config.isBetterThan(best_value->config, &match)) {
164 if (value->config.compare(best_value->config) != 0) {
165 continue;
166 }
167 }
168 }
169
170 best_value = value.get();
171 }
172
173 // The entry has no values
174 if (!best_value) {
175 return nullptr;
176 }
177
178 return best_value->value.get();
179 }
180
181 /** Retrieves the resource assigned to the specified resource id if one exists. */
182 Value* FindValueById(const ResourceTable* table, const ResourceId& res_id,
183 const ConfigDescription& config = DummyConfig()) {
184 if (table) {
185 for (auto& package : table->packages) {
186 if (package->id && package->id.value() == res_id.package_id()) {
187 for (auto& type : package->types) {
188 if (type->id && type->id.value() == res_id.type_id()) {
189 for (auto& entry : type->entries) {
190 if (entry->id && entry->id.value() == res_id.entry_id()) {
191 if (auto value = BestConfigValue(entry.get(), config)) {
192 return value;
193 }
194 }
195 }
196 }
197 }
198 }
199 }
200 }
201 return nullptr;
202 }
203
204 /** Attempts to resolve the reference to a non-reference value. */
205 Value* ResolveReference(Reference* ref, const ConfigDescription& config = DummyConfig()) {
206 const int kMaxIterations = 40;
207 int i = 0;
208 while (ref && ref->id && i++ < kMaxIterations) {
209 auto table = extractor_->apk_->GetResourceTable();
210 if (auto value = FindValueById(table, ref->id.value(), config)) {
211 if (ValueCast<Reference>(value)) {
212 ref = ValueCast<Reference>(value);
213 } else {
214 return value;
215 }
216 }
217 }
218 return nullptr;
219 }
220
221 /**
222 * Retrieves the integer value of the attribute . If the value of the attribute is a reference,
223 * this will attempt to resolve the reference to an integer value.
224 **/
225 int32_t* GetAttributeInteger(xml::Attribute* attr,
226 const ConfigDescription& config = DummyConfig()) {
227 if (attr != nullptr) {
228 if (attr->compiled_value) {
229 // Resolve references using the dummy configuration
230 Value* value = attr->compiled_value.get();
231 if (ValueCast<Reference>(value)) {
232 value = ResolveReference(ValueCast<Reference>(value), config);
233 } else {
234 value = attr->compiled_value.get();
235 }
236 // Retrieve the integer data if possible
237 if (value != nullptr) {
238 if (BinaryPrimitive* intValue = ValueCast<BinaryPrimitive>(value)) {
239 return (int32_t*) &intValue->value.data;
240 }
241 }
242 }
243 }
244 return nullptr;
245 }
246
247 /**
248 * A version of GetAttributeInteger that returns a default integer if the attribute does not
249 * exist or cannot be resolved to an integer value.
250 **/
251 int32_t GetAttributeIntegerDefault(xml::Attribute* attr, int32_t def,
252 const ConfigDescription& config = DummyConfig()) {
253 auto value = GetAttributeInteger(attr, config);
254 if (value) {
255 return *value;
256 }
257 return def;
258 }
259
260 /**
261 * Retrieves the string value of the attribute. If the value of the attribute is a reference,
262 * this will attempt to resolve the reference to a string value.
263 **/
264 const std::string* GetAttributeString(xml::Attribute* attr,
265 const ConfigDescription& config = DummyConfig()) {
266 if (attr != nullptr) {
267 if (attr->compiled_value) {
268 // Resolve references using the dummy configuration
269 Value* value = attr->compiled_value.get();
270 if (ValueCast<Reference>(value)) {
271 value = ResolveReference(ValueCast<Reference>(value), config);
272 } else {
273 value = attr->compiled_value.get();
274 }
275
276 // Retrieve the string data of the value if possible
277 if (value != nullptr) {
278 if (String* intValue = ValueCast<String>(value)) {
279 return &(*intValue->value);
280 } else if (RawString* rawValue = ValueCast<RawString>(value)) {
281 return &(*rawValue->value);
282 } else if (FileReference* strValue = ValueCast<FileReference>(value)) {
283 return &(*strValue->path);
284 }
285 }
286 }
287 return &attr->value;
288 }
289 return nullptr;
290 }
291
292 /**
293 * A version of GetAttributeString that returns a default string if the attribute does not
294 * exist or cannot be resolved to an string value.
295 **/
296 std::string GetAttributeStringDefault(xml::Attribute* attr, std::string def,
297 const ConfigDescription& config = DummyConfig()) {
298 auto value = GetAttributeString(attr, config);
299 if (value) {
300 return *value;
301 }
302 return def;
303 }
304
305 private:
306 ManifestExtractor* extractor_;
307 std::vector<std::unique_ptr<Element>> children_;
308 std::string tag_;
309 };
310
311 friend Element;
312
313 /** Creates a default configuration used to retrieve resources. */
314 static ConfigDescription DummyConfig() {
315 ConfigDescription config;
316 config.orientation = android::ResTable_config::ORIENTATION_PORT;
317 config.density = android::ResTable_config::DENSITY_MEDIUM;
318 config.sdkVersion = 10000; // Very high.
319 config.screenWidthDp = 320;
320 config.screenHeightDp = 480;
321 config.smallestScreenWidthDp = 320;
322 config.screenLayout |= android::ResTable_config::SCREENSIZE_NORMAL;
323 return config;
324 }
325
326 bool Dump(text::Printer& printer, IDiagnostics* diag);
327
328 /** Recursively visit the xml element tree and return a processed badging element tree. */
329 std::unique_ptr<Element> Visit(xml::Element* element);
330
331 /** Raises the target sdk value if the min target is greater than the current target. */
332 void RaiseTargetSdk(int32_t min_target) {
333 if (min_target > target_sdk_) {
334 target_sdk_ = min_target;
335 }
336 }
337
338 /**
339 * Retrieves the default feature group that features are added into when <uses-feature>
340 * are not in a <feature-group> element.
341 **/
342 CommonFeatureGroup* GetCommonFeatureGroup() {
343 return commonFeatureGroup_.get();
344 }
345
346 /**
347 * Retrieves a mapping of density values to Configurations for retrieving resources that would be
348 * used for that density setting.
349 **/
350 const std::map<uint16_t, ConfigDescription> densities() const {
351 return densities_;
352 }
353
354 /**
355 * Retrieves a mapping of locale BCP 47 strings to Configurations for retrieving resources that
356 * would be used for that locale setting.
357 **/
358 const std::map<std::string, ConfigDescription> locales() const {
359 return locales_;
360 }
361
362 /** Retrieves the current stack of parent during data extraction. */
363 const std::vector<Element*> parent_stack() const {
364 return parent_stack_;
365 }
366
367 int32_t target_sdk() const {
368 return target_sdk_;
369 }
370
371 LoadedApk* const apk_;
372 const Options options_;
373
374 private:
375 std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
376 std::map<std::string, ConfigDescription> locales_;
377 std::map<uint16_t, ConfigDescription> densities_;
378 std::vector<Element*> parent_stack_;
379 int32_t target_sdk_ = 0;
380};
381
382template<typename T> T* ElementCast(ManifestExtractor::Element* element);
383
384/** Recurs through the children of the specified root in depth-first order. */
385static void ForEachChild(ManifestExtractor::Element* root,
386 std::function<void(ManifestExtractor::Element*)> f) {
387 for (auto& child : root->children()) {
388 f(child.get());
389 ForEachChild(child.get(), f);
390 }
391}
392
393/**
394 * Checks the element and its recursive children for an element that makes the specified
395 * conditional function return true. Returns the first element that makes the conditional function
396 * return true.
397 **/
398static ManifestExtractor::Element* FindElement(ManifestExtractor::Element* root,
399 std::function<bool(ManifestExtractor::Element*)> f) {
400 if (f(root)) {
401 return root;
402 }
403 for (auto& child : root->children()) {
404 if (auto b2 = FindElement(child.get(), f)) {
405 return b2;
406 }
407 }
408 return nullptr;
409}
410
411/** Represents the <manifest> elements **/
412class Manifest : public ManifestExtractor::Element {
413 public:
414 Manifest() = default;
415 std::string package;
416 int32_t versionCode;
417 std::string versionName;
418 const std::string* split = nullptr;
419 const std::string* platformVersionName = nullptr;
420 const std::string* platformVersionCode = nullptr;
421 const int32_t* compilesdkVersion = nullptr;
422 const std::string* compilesdkVersionCodename = nullptr;
423 const int32_t* installLocation = nullptr;
424
425 void Extract(xml::Element* manifest) override {
426 package = GetAttributeStringDefault(FindAttribute(manifest, {}, "package"), "");
427 versionCode = GetAttributeIntegerDefault(FindAttribute(manifest, VERSION_CODE_ATTR), 0);
428 versionName = GetAttributeStringDefault(FindAttribute(manifest, VERSION_NAME_ATTR), "");
429 split = GetAttributeString(FindAttribute(manifest, {}, "split"));
430
431 // Extract the platform build info
432 platformVersionName = GetAttributeString(FindAttribute(manifest, {},
433 "platformBuildVersionName"));
434 platformVersionCode = GetAttributeString(FindAttribute(manifest, {},
435 "platformBuildVersionCode"));
436
437 // Extract the compile sdk info
438 compilesdkVersion = GetAttributeInteger(FindAttribute(manifest, COMPILE_SDK_VERSION_ATTR));
439 compilesdkVersionCodename = GetAttributeString(
440 FindAttribute(manifest, COMPILE_SDK_VERSION_CODENAME_ATTR));
441 installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR));
442 }
443
444 void Print(text::Printer& printer) override {
445 printer.Print(StringPrintf("package: name='%s' ", package.data()));
446 printer.Print(StringPrintf("versionCode='%s' ",
447 (versionCode > 0) ? std::to_string(versionCode).data() : ""));
448 printer.Print(StringPrintf("versionName='%s'", versionName.data()));
449
450 if (split) {
451 printer.Print(StringPrintf(" split='%s'", split->data()));
452 }
453 if (platformVersionName) {
454 printer.Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
455 }
456 if (platformVersionCode) {
457 printer.Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
458 }
459 if (compilesdkVersion) {
460 printer.Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion));
461 }
462 if (compilesdkVersionCodename) {
463 printer.Print(StringPrintf(" compileSdkVersionCodename='%s'",
464 compilesdkVersionCodename->data()));
465 }
466 printer.Print("\n");
467
468 if (installLocation) {
469 switch (*installLocation) {
470 case 0:
471 printer.Print("install-location:'auto'\n");
472 break;
473 case 1:
474 printer.Print("install-location:'internalOnly'\n");
475 break;
476 case 2:
477 printer.Print("install-location:'preferExternal'\n");
478 break;
479 default:
480 break;
481 }
482 }
483 }
484};
485
486/** Represents <application> elements. **/
487class Application : public ManifestExtractor::Element {
488 public:
489 Application() = default;
490 std::string label;
491 std::string icon;
492 std::string banner;
493 int32_t is_game;
494 int32_t debuggable;
495 int32_t test_only;
496 bool has_multi_arch;
497
498 /** Mapping from locales to app names. */
499 std::map<std::string, std::string> locale_labels;
500
501 /** Mapping from densities to app icons. */
502 std::map<uint16_t, std::string> density_icons;
503
504 void Extract(xml::Element* element) override {
505 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
506 icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
507 test_only = GetAttributeIntegerDefault(FindAttribute(element, TEST_ONLY_ATTR), 0);
508 banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
509 is_game = GetAttributeIntegerDefault(FindAttribute(element, ISGAME_ATTR), 0);
510 debuggable = GetAttributeIntegerDefault(FindAttribute(element, DEBUGGABLE_ATTR), 0);
511
512 // We must search by name because the multiArch flag hasn't been API
513 // frozen yet.
514 has_multi_arch = (GetAttributeIntegerDefault(
515 FindAttribute(element, kAndroidNamespace, "multiArch"), 0) != 0);
516
517 // Retrieve the app names for every locale the app supports
518 auto attr = FindAttribute(element, LABEL_ATTR);
519 for (auto& config : extractor()->locales()) {
520 if (auto label = GetAttributeString(attr, config.second)) {
521 if (label) {
522 locale_labels.insert(std::make_pair(config.first, *label));
523 }
524 }
525 }
526
527 // Retrieve the icons for the densities the app supports
528 attr = FindAttribute(element, ICON_ATTR);
529 for (auto& config : extractor()->densities()) {
530 if (auto resource = GetAttributeString(attr, config.second)) {
531 if (resource) {
532 density_icons.insert(std::make_pair(config.first, *resource));
533 }
534 }
535 }
536 }
537
538 void Print(text::Printer& printer) override {
539 // Print the labels for every locale
540 for (auto p : locale_labels) {
541 if (p.first.empty()) {
542 printer.Print(StringPrintf("application-label:'%s'\n",
543 android::ResTable::normalizeForOutput(p.second.data())
544 .c_str()));
545 } else {
546 printer.Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(),
547 android::ResTable::normalizeForOutput(p.second.data())
548 .c_str()));
549 }
550 }
551
552 // Print the icon paths for every density
553 for (auto p : density_icons) {
554 printer.Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data()));
555 }
556
557 // Print the application info
558 printer.Print(StringPrintf("application: label='%s' ",
559 android::ResTable::normalizeForOutput(label.data()).c_str()));
560 printer.Print(StringPrintf("icon='%s'", icon.data()));
561 if (!banner.empty()) {
562 printer.Print(StringPrintf(" banner='%s'", banner.data()));
563 }
564 printer.Print("\n");
565
566 if (test_only != 0) {
567 printer.Print(StringPrintf("testOnly='%d'\n", test_only));
568 }
569 if (is_game != 0) {
570 printer.Print("application-isGame\n");
571 }
572 if (debuggable != 0) {
573 printer.Print("application-debuggable\n");
574 }
575 }
576};
577
578/** Represents <uses-sdk> elements. **/
579class UsesSdkBadging : public ManifestExtractor::Element {
580 public:
581 UsesSdkBadging() = default;
582 const int32_t* min_sdk = nullptr;
583 const std::string* min_sdk_name = nullptr;
584 const int32_t* max_sdk = nullptr;
585 const int32_t* target_sdk = nullptr;
586 const std::string* target_sdk_name = nullptr;
587
588 void Extract(xml::Element* element) override {
589 min_sdk = GetAttributeInteger(FindAttribute(element, MIN_SDK_VERSION_ATTR));
590 min_sdk_name = GetAttributeString(FindAttribute(element, MIN_SDK_VERSION_ATTR));
591 max_sdk = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
592 target_sdk = GetAttributeInteger(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
593 target_sdk_name = GetAttributeString(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
594
595 // Detect the target sdk of the element
596 if ((min_sdk_name && *min_sdk_name == "Donut")
597 || (target_sdk_name && *target_sdk_name == "Donut")) {
598 extractor()->RaiseTargetSdk(4);
599 }
600 if (min_sdk) {
601 extractor()->RaiseTargetSdk(*min_sdk);
602 }
603 if (target_sdk) {
604 extractor()->RaiseTargetSdk(*target_sdk);
605 }
606 }
607
608 void Print(text::Printer& printer) override {
609 if (min_sdk) {
610 printer.Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk));
611 } else if (min_sdk_name) {
612 printer.Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data()));
613 }
614 if (max_sdk) {
615 printer.Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk));
616 }
617 if (target_sdk) {
618 printer.Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk));
619 } else if (target_sdk_name) {
620 printer.Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
621 }
622 }
623};
624
625/** Represents <uses-configuration> elements. **/
626class UsesConfiguarion : public ManifestExtractor::Element {
627 public:
628 UsesConfiguarion() = default;
629 int32_t req_touch_screen = 0;
630 int32_t req_keyboard_type = 0;
631 int32_t req_hard_keyboard = 0;
632 int32_t req_navigation = 0;
633 int32_t req_five_way_nav = 0;
634
635 void Extract(xml::Element* element) override {
636 req_touch_screen = GetAttributeIntegerDefault(
637 FindAttribute(element, REQ_TOUCH_SCREEN_ATTR), 0);
638 req_keyboard_type = GetAttributeIntegerDefault(
639 FindAttribute(element, REQ_KEYBOARD_TYPE_ATTR), 0);
640 req_hard_keyboard = GetAttributeIntegerDefault(
641 FindAttribute(element, REQ_HARD_KEYBOARD_ATTR), 0);
642 req_navigation = GetAttributeIntegerDefault(
643 FindAttribute(element, REQ_NAVIGATION_ATTR), 0);
644 req_five_way_nav = GetAttributeIntegerDefault(
645 FindAttribute(element, REQ_FIVE_WAY_NAV_ATTR), 0);
646 }
647
648 void Print(text::Printer& printer) override {
649 printer.Print("uses-configuration:");
650 if (req_touch_screen != 0) {
651 printer.Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen));
652 }
653 if (req_keyboard_type != 0) {
654 printer.Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type));
655 }
656 if (req_hard_keyboard != 0) {
657 printer.Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard));
658 }
659 if (req_navigation != 0) {
660 printer.Print(StringPrintf(" reqNavigation='%d'", req_navigation));
661 }
662 if (req_five_way_nav != 0) {
663 printer.Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav));
664 }
665 printer.Print("\n");
666 }
667};
668
669/** Represents <supports-screen> elements. **/
670class SupportsScreen : public ManifestExtractor::Element {
671 public:
672 SupportsScreen() = default;
673 int32_t small_screen = 1;
674 int32_t normal_screen = 1;
675 int32_t large_screen = 1;
676 int32_t xlarge_screen = 1;
677 int32_t any_density = 1;
678 int32_t requires_smallest_width_dp = 0;
679 int32_t compatible_width_limit_dp = 0;
680 int32_t largest_width_limit_dp = 0;
681
682 void Extract(xml::Element* element) override {
683 small_screen = GetAttributeIntegerDefault(FindAttribute(element, SMALL_SCREEN_ATTR), 1);
684 normal_screen = GetAttributeIntegerDefault(FindAttribute(element, NORMAL_SCREEN_ATTR), 1);
685 large_screen = GetAttributeIntegerDefault(FindAttribute(element, LARGE_SCREEN_ATTR), 1);
686 xlarge_screen = GetAttributeIntegerDefault(FindAttribute(element, XLARGE_SCREEN_ATTR), 1);
687 any_density = GetAttributeIntegerDefault(FindAttribute(element, ANY_DENSITY_ATTR), 1);
688
689 requires_smallest_width_dp = GetAttributeIntegerDefault(
690 FindAttribute(element, REQUIRES_SMALLEST_WIDTH_DP_ATTR), 0);
691 compatible_width_limit_dp = GetAttributeIntegerDefault(
692 FindAttribute(element, COMPATIBLE_WIDTH_LIMIT_DP_ATTR), 0);
693 largest_width_limit_dp = GetAttributeIntegerDefault(
694 FindAttribute(element, LARGEST_WIDTH_LIMIT_DP_ATTR), 0);
695
696 // For modern apps, if screen size buckets haven't been specified
697 // but the new width ranges have, then infer the buckets from them.
698 if (small_screen > 0 && normal_screen > 0 && large_screen > 0 && xlarge_screen > 0
699 && requires_smallest_width_dp > 0) {
700 int32_t compat_width = (compatible_width_limit_dp > 0) ? compatible_width_limit_dp
701 : requires_smallest_width_dp;
702 small_screen = (requires_smallest_width_dp <= 240 && compat_width >= 240) ? -1 : 0;
703 normal_screen = (requires_smallest_width_dp <= 320 && compat_width >= 320) ? -1 : 0;
704 large_screen = (requires_smallest_width_dp <= 480 && compat_width >= 480) ? -1 : 0;
705 xlarge_screen = (requires_smallest_width_dp <= 720 && compat_width >= 720) ? -1 : 0;
706 }
707 }
708
709 void PrintScreens(text::Printer& printer, int32_t target_sdk) {
710 int32_t small_screen_temp = small_screen;
711 int32_t normal_screen_temp = normal_screen;
712 int32_t large_screen_temp = large_screen;
713 int32_t xlarge_screen_temp = xlarge_screen;
714 int32_t any_density_temp = any_density;
715
716 // Determine default values for any unspecified screen sizes,
717 // based on the target SDK of the package. As of 4 (donut)
718 // the screen size support was introduced, so all default to
719 // enabled.
720 if (small_screen_temp > 0) {
721 small_screen_temp = target_sdk >= 4 ? -1 : 0;
722 }
723 if (normal_screen_temp > 0) {
724 normal_screen_temp = -1;
725 }
726 if (large_screen_temp > 0) {
727 large_screen_temp = target_sdk >= 4 ? -1 : 0;
728 }
729 if (xlarge_screen_temp > 0) {
730 // Introduced in Gingerbread.
731 xlarge_screen_temp = target_sdk >= 9 ? -1 : 0;
732 }
733 if (any_density_temp > 0) {
734 any_density_temp = (target_sdk >= 4 || requires_smallest_width_dp > 0
735 || compatible_width_limit_dp > 0) ? -1 : 0;
736 }
737
738 // Print the formatted screen info
739 printer.Print("supports-screens:");
740 if (small_screen_temp != 0) {
741 printer.Print(" 'small'");
742 }
743 if (normal_screen_temp != 0) {
744 printer.Print(" 'normal'");
745 }
746 if (large_screen_temp != 0) {
747 printer.Print(" 'large'");
748 }
749 if (xlarge_screen_temp != 0) {
750 printer.Print(" 'xlarge'");
751 }
752 printer.Print("\n");
753 printer.Print(StringPrintf("supports-any-density: '%s'\n",
754 (any_density_temp ) ? "true" : "false"));
755 if (requires_smallest_width_dp > 0) {
756 printer.Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
757 }
758 if (compatible_width_limit_dp > 0) {
759 printer.Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp));
760 }
761 if (largest_width_limit_dp > 0) {
762 printer.Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
763 }
764 }
765};
766
767/** Represents <feature-group> elements. **/
768class FeatureGroup : public ManifestExtractor::Element {
769 public:
770 FeatureGroup() = default;
771 std::string label;
772 int32_t open_gles_version = 0;
773
774 void Extract(xml::Element* element) override {
775 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
776 }
777
778 virtual void PrintGroup(text::Printer& printer) {
779 printer.Print(StringPrintf("feature-group: label='%s'\n", label.data()));
780 if (open_gles_version > 0) {
781 printer.Print(StringPrintf(" uses-gl-es: '0x%x'\n", open_gles_version));
782 }
783
784 for (auto feature : features_) {
785 printer.Print(StringPrintf(" uses-feature%s: name='%s'",
786 (feature.second.required ? "" : "-not-required"),
787 feature.first.data()));
788 if (feature.second.version > 0) {
789 printer.Print(StringPrintf(" version='%d'", feature.second.version));
790 }
791 printer.Print("\n");
792 }
793 }
794
795 /** Adds a feature to the feature group. */
796 void AddFeature(const std::string& name, bool required = true, int32_t version = -1) {
797 features_.insert(std::make_pair(name, Feature{ required, version }));
798 if (required) {
799 if (name == "android.hardware.camera.autofocus" ||
800 name == "android.hardware.camera.flash") {
801 AddFeature("android.hardware.camera", true);
802 } else if (name == "android.hardware.location.gps" ||
803 name == "android.hardware.location.network") {
804 AddFeature("android.hardware.location", true);
805 } else if (name == "android.hardware.faketouch.multitouch") {
806 AddFeature("android.hardware.faketouch", true);
807 } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
808 name == "android.hardware.faketouch.multitouch.jazzhands") {
809 AddFeature("android.hardware.faketouch.multitouch", true);
810 AddFeature("android.hardware.faketouch", true);
811 } else if (name == "android.hardware.touchscreen.multitouch") {
812 AddFeature("android.hardware.touchscreen", true);
813 } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
814 name == "android.hardware.touchscreen.multitouch.jazzhands") {
815 AddFeature("android.hardware.touchscreen.multitouch", true);
816 AddFeature("android.hardware.touchscreen", true);
817 } else if (name == "android.hardware.opengles.aep") {
818 const int kOpenGLESVersion31 = 0x00030001;
819 if (kOpenGLESVersion31 > open_gles_version) {
820 open_gles_version = kOpenGLESVersion31;
821 }
822 }
823 }
824 }
825
826 /** Returns true if the feature group has the given feature. */
827 virtual bool HasFeature(const std::string& name) {
828 return features_.find(name) != features_.end();
829 }
830
831 /** Merges the features of another feature group into this group. */
832 void Merge(FeatureGroup* group) {
833 open_gles_version = std::max(open_gles_version, group->open_gles_version);
834 for (auto& feature : group->features_) {
835 features_.insert(feature);
836 }
837 }
838
839 protected:
840 struct Feature {
841 public:
842 bool required = false;
843 int32_t version = -1;
844 };
845
846 /* Mapping of feature names to their properties. */
847 std::map<std::string, Feature> features_;
848};
849
850/**
851 * Represents the default feature group for the application if no <feature-group> elements are
852 * present in the manifest.
853 **/
854class CommonFeatureGroup : public FeatureGroup {
855 public:
856 CommonFeatureGroup() = default;
857 void PrintGroup(text::Printer& printer) override {
858 FeatureGroup::PrintGroup(printer);
859
860 // Also print the implied features
861 for (auto feature : implied_features_) {
862 if (features_.find(feature.first) == features_.end()) {
863 const char* sdk23 = feature.second.implied_from_sdk_k23 ? "-sdk-23" : "";
864 printer.Print(StringPrintf(" uses-feature%s: name='%s'\n", sdk23, feature.first.data()));
865 printer.Print(StringPrintf(" uses-implied-feature%s: name='%s' reason='", sdk23,
866 feature.first.data()));
867
868 // Print the reasons as a sentence
869 size_t count = 0;
870 for (auto reason : feature.second.reasons) {
871 printer.Print(reason);
872 if (count + 2 < feature.second.reasons.size()) {
873 printer.Print(", ");
874 } else if (count + 1 < feature.second.reasons.size()) {
875 printer.Print(", and ");
876 }
877 count++;
878 }
879 printer.Print("'\n");
880 }
881 }
882 }
883
884 /** Returns true if the feature group has the given feature. */
885 bool HasFeature(const std::string& name) override {
886 return FeatureGroup::HasFeature(name)
887 || implied_features_.find(name) != implied_features_.end();
888 }
889
890 /** Adds a feature to a set of implied features not explicitly requested in the manifest. */
891 void addImpliedFeature(const std::string& name, const std::string& reason, bool sdk23 = false) {
892 auto entry = implied_features_.find(name);
893 if (entry == implied_features_.end()) {
894 implied_features_.insert(std::make_pair(name, ImpliedFeature(sdk23)));
895 entry = implied_features_.find(name);
896 }
897
898 // A non-sdk 23 implied feature takes precedence.
899 if (entry->second.implied_from_sdk_k23 && !sdk23) {
900 entry->second.implied_from_sdk_k23 = false;
901 }
902
903 entry->second.reasons.insert(reason);
904 }
905
906 /**
907 * Adds a feature to a set of implied features for all features that are implied by the presence
908 * of the permission.
909 **/
910 void addImpliedFeaturesForPermission(int32_t targetSdk, const std::string& name, bool sdk23) {
911 if (name == "android.permission.CAMERA") {
912 addImpliedFeature("android.hardware.camera",
913 StringPrintf("requested %s permission", name.data()),
914 sdk23);
915
916 } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
917 if (targetSdk < SDK_LOLLIPOP) {
918 addImpliedFeature("android.hardware.location.gps",
919 StringPrintf("requested %s permission", name.data()),
920 sdk23);
921 addImpliedFeature("android.hardware.location.gps",
922 StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
923 sdk23);
924 }
925 addImpliedFeature("android.hardware.location",
926 StringPrintf("requested %s permission", name.data()),
927 sdk23);
928
929 } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
930 if (targetSdk < SDK_LOLLIPOP) {
931 addImpliedFeature("android.hardware.location.network",
932 StringPrintf("requested %s permission", name.data()),
933 sdk23);
934 addImpliedFeature("android.hardware.location.network",
935 StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
936 sdk23);
937 }
938 addImpliedFeature("android.hardware.location",
939 StringPrintf("requested %s permission", name.data()),
940 sdk23);
941
942 } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
943 name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
944 name == "android.permission.INSTALL_LOCATION_PROVIDER") {
945 addImpliedFeature("android.hardware.location",
946 StringPrintf("requested %s permission", name.data()),
947 sdk23);
948
949 } else if (name == "android.permission.BLUETOOTH" ||
950 name == "android.permission.BLUETOOTH_ADMIN") {
951 if (targetSdk > SDK_DONUT) {
952 addImpliedFeature("android.hardware.bluetooth",
953 StringPrintf("requested %s permission", name.data()),
954 sdk23);
955 addImpliedFeature("android.hardware.bluetooth",
956 StringPrintf("targetSdkVersion > %d", SDK_DONUT),
957 sdk23);
958 }
959
960 } else if (name == "android.permission.RECORD_AUDIO") {
961 addImpliedFeature("android.hardware.microphone",
962 StringPrintf("requested %s permission", name.data()),
963 sdk23);
964
965 } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
966 name == "android.permission.CHANGE_WIFI_STATE" ||
967 name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
968 addImpliedFeature("android.hardware.wifi",
969 StringPrintf("requested %s permission", name.data()),
970 sdk23);
971
972 } else if (name == "android.permission.CALL_PHONE" ||
973 name == "android.permission.CALL_PRIVILEGED" ||
974 name == "android.permission.MODIFY_PHONE_STATE" ||
975 name == "android.permission.PROCESS_OUTGOING_CALLS" ||
976 name == "android.permission.READ_SMS" ||
977 name == "android.permission.RECEIVE_SMS" ||
978 name == "android.permission.RECEIVE_MMS" ||
979 name == "android.permission.RECEIVE_WAP_PUSH" ||
980 name == "android.permission.SEND_SMS" ||
981 name == "android.permission.WRITE_APN_SETTINGS" ||
982 name == "android.permission.WRITE_SMS") {
983 addImpliedFeature("android.hardware.telephony",
984 "requested a telephony permission",
985 sdk23);
986 }
987 }
988
989 private:
990 /**
991 * Represents a feature that has been automatically added due to a pre-requisite or for some
992 * other reason.
993 */
994 struct ImpliedFeature {
995 explicit ImpliedFeature(bool sdk23 = false) : implied_from_sdk_k23(sdk23) {}
996
997 /** List of human-readable reasons for why this feature was implied. */
998 std::set<std::string> reasons;
999
1000 // Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)
1001 bool implied_from_sdk_k23;
1002 };
1003
1004 /* Mapping of implied feature names to their properties. */
1005 std::map<std::string, ImpliedFeature> implied_features_;
1006};
1007
1008/** Represents <uses-feature> elements. **/
1009class UsesFeature : public ManifestExtractor::Element {
1010 public:
1011 UsesFeature() = default;
1012 void Extract(xml::Element* element) override {
1013 const std::string* name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1014 int32_t* gl = GetAttributeInteger(FindAttribute(element, GL_ES_VERSION_ATTR));
1015 bool required = GetAttributeIntegerDefault(
1016 FindAttribute(element, REQUIRED_ATTR), true) != 0;
1017 int32_t version = GetAttributeIntegerDefault(
1018 FindAttribute(element, kAndroidNamespace, "version"), 0);
1019
1020 // Add the feature to the parent feature group element if one exists; otherwise, add it to the
1021 // common feature group
1022 FeatureGroup* feature_group = ElementCast<FeatureGroup>(extractor()->parent_stack()[0]);
1023 if (!feature_group) {
1024 feature_group = extractor()->GetCommonFeatureGroup();
1025 } else {
1026 // All features in side of <feature-group> elements are required.
1027 required = true;
1028 }
1029
1030 if (name) {
1031 feature_group->AddFeature(*name, required, version);
1032 } else if (gl) {
1033 feature_group->open_gles_version = std::max(feature_group->open_gles_version, *gl);
1034 }
1035 }
1036};
1037
1038/** Represents <uses-permission> elements. **/
1039class UsesPermission : public ManifestExtractor::Element {
1040 public:
1041 UsesPermission() = default;
1042 std::string name;
1043 std::string requiredFeature;
1044 std::string requiredNotFeature;
1045 int32_t required = true;
1046 int32_t maxSdkVersion = -1;
1047
1048 void Extract(xml::Element* element) override {
1049 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1050 requiredFeature = GetAttributeStringDefault(
1051 FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
1052 requiredNotFeature = GetAttributeStringDefault(
1053 FindAttribute(element, REQUIRED_NOT_FEATURE_ATTR), "");
1054 required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
1055 maxSdkVersion = GetAttributeIntegerDefault(
1056 FindAttribute(element, MAX_SDK_VERSION_ATTR), -1);
1057
1058 if (!name.empty()) {
1059 CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
1060 common->addImpliedFeaturesForPermission(extractor()->target_sdk(), name, false);
1061 }
1062 }
1063
1064 void Print(text::Printer& printer) override {
1065 if (!name.empty()) {
1066 printer.Print(StringPrintf("uses-permission: name='%s'", name.data()));
1067 if (maxSdkVersion >= 0) {
1068 printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
1069 }
1070 if (!requiredFeature.empty()) {
1071 printer.Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data()));
1072 }
1073 if (!requiredNotFeature.empty()) {
1074 printer.Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data()));
1075 }
1076 printer.Print("\n");
1077 if (required == 0) {
1078 printer.Print(StringPrintf("optional-permission: name='%s'", name.data()));
1079 if (maxSdkVersion >= 0) {
1080 printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
1081 }
1082 printer.Print("\n");
1083 }
1084 }
1085 }
1086
1087 void PrintImplied(text::Printer& printer, const std::string& reason) {
1088 printer.Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
1089 if (maxSdkVersion >= 0) {
1090 printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
1091 }
1092 printer.Print(StringPrintf(" reason='%s'\n", reason.data()));
1093 }
1094};
1095
1096/** Represents <uses-permission-sdk-23> elements. **/
1097class UsesPermissionSdk23 : public ManifestExtractor::Element {
1098 public:
1099 UsesPermissionSdk23() = default;
1100 const std::string* name = nullptr;
1101 const int32_t* maxSdkVersion = nullptr;
1102
1103 void Extract(xml::Element* element) override {
1104 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1105 maxSdkVersion = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
1106
1107 if (name) {
1108 CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
1109 common->addImpliedFeaturesForPermission(extractor()->target_sdk(), *name, true);
1110 }
1111 }
1112
1113 void Print(text::Printer& printer) override {
1114 if (name) {
1115 printer.Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data()));
1116 if (maxSdkVersion) {
1117 printer.Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion));
1118 }
1119 printer.Print("\n");
1120 }
1121 }
1122};
1123
1124/** Represents <permission> elements. These elements are only printing when dumping permissions. **/
1125class Permission : public ManifestExtractor::Element {
1126 public:
1127 Permission() = default;
1128 std::string name;
1129
1130 void Extract(xml::Element* element) override {
1131 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1132 }
1133
1134 void Print(text::Printer& printer) override {
1135 if (extractor()->options_.only_permissions && !name.empty()) {
1136 printer.Print(StringPrintf("permission: %s\n", name.data()));
1137 }
1138 }
1139};
1140
1141/** Represents <activity> elements. **/
1142class Activity : public ManifestExtractor::Element {
1143 public:
1144 Activity() = default;
1145 std::string name;
1146 std::string icon;
1147 std::string label;
1148 std::string banner;
1149
1150 bool has_component_ = false;
1151 bool has_launcher_category = false;
1152 bool has_leanback_launcher_category = false;
1153 bool has_main_action = false;
1154
1155 void Extract(xml::Element* element) override {
1156 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1157 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
1158 icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
1159 banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
1160
1161 // Retrieve the package name from the manifest
1162 std::string package;
1163 for (auto& parent : extractor()->parent_stack()) {
1164 if (auto manifest = ElementCast<Manifest>(parent)) {
1165 package = manifest->package;
1166 break;
1167 }
1168 }
1169
1170 // Fully qualify the activity name
1171 ssize_t idx = name.find(".");
1172 if (idx == 0) {
1173 name = package + name;
1174 } else if (idx < 0) {
1175 name = package + "." + name;
1176 }
1177
1178 auto orientation = GetAttributeInteger(FindAttribute(element, SCREEN_ORIENTATION_ATTR));
1179 if (orientation) {
1180 CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
1181 int orien = *orientation;
1182 if (orien == 0 || orien == 6 || orien == 8) {
1183 // Requests landscape, sensorLandscape, or reverseLandscape.
1184 common->addImpliedFeature("android.hardware.screen.landscape",
1185 "one or more activities have specified a landscape orientation",
1186 false);
1187 } else if (orien == 1 || orien == 7 || orien == 9) {
1188 // Requests portrait, sensorPortrait, or reversePortrait.
1189 common->addImpliedFeature("android.hardware.screen.portrait",
1190 "one or more activities have specified a portrait orientation",
1191 false);
1192 }
1193 }
1194 }
1195
1196 void Print(text::Printer& printer) override {
1197 // Print whether the activity has the HOME category and a the MAIN action
1198 if (has_main_action && has_launcher_category) {
1199 printer.Print("launchable-activity:");
1200 if (!name.empty()) {
1201 printer.Print(StringPrintf(" name='%s' ", name.data()));
1202 }
1203 printer.Print(StringPrintf(" label='%s' icon='%s'\n",
1204 android::ResTable::normalizeForOutput(label.data()).c_str(),
1205 icon.data()));
1206 }
1207
1208 // Print wether the activity has the HOME category and a the MAIN action
1209 if (has_leanback_launcher_category) {
1210 printer.Print("leanback-launchable-activity:");
1211 if (!name.empty()) {
1212 printer.Print(StringPrintf(" name='%s' ", name.data()));
1213 }
1214 printer.Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n",
1215 android::ResTable::normalizeForOutput(label.data()).c_str(),
1216 icon.data(), banner.data()));
1217 }
1218 }
1219};
1220
1221/** Represents <intent-filter> elements. */
1222class IntentFilter : public ManifestExtractor::Element {
1223 public:
1224 IntentFilter() = default;
1225};
1226
1227/** Represents <category> elements. */
1228class Category : public ManifestExtractor::Element {
1229 public:
1230 Category() = default;
1231 std::string component = "";
1232
1233 void Extract(xml::Element* element) override {
1234 const std::string* category = GetAttributeString(FindAttribute(element, NAME_ATTR));
1235
1236 auto parent_stack = extractor()->parent_stack();
1237 if (category && ElementCast<IntentFilter>(parent_stack[0])
1238 && ElementCast<Activity>(parent_stack[1])) {
1239 Activity* activity = ElementCast<Activity>(parent_stack[1]);
1240
1241 if (*category == "android.intent.category.LAUNCHER") {
1242 activity->has_launcher_category = true;
1243 } else if (*category == "android.intent.category.LEANBACK_LAUNCHER") {
1244 activity->has_leanback_launcher_category = true;
1245 } else if (*category == "android.intent.category.HOME") {
1246 component = "launcher";
1247 }
1248 }
1249 }
1250};
1251
1252/**
1253 * Represents <provider> elements. The elements may have an <intent-filter> which may have <action>
1254 * elements nested within.
1255 **/
1256class Provider : public ManifestExtractor::Element {
1257 public:
1258 Provider() = default;
1259 bool has_required_saf_attributes = false;
1260
1261 void Extract(xml::Element* element) override {
1262 const int32_t* exported = GetAttributeInteger(FindAttribute(element, EXPORTED_ATTR));
1263 const int32_t* grant_uri_permissions = GetAttributeInteger(
1264 FindAttribute(element, GRANT_URI_PERMISSIONS_ATTR));
1265 const std::string* permission = GetAttributeString(
1266 FindAttribute(element, PERMISSION_ATTR));
1267
1268 has_required_saf_attributes = ((exported && *exported != 0)
1269 && (grant_uri_permissions && *grant_uri_permissions != 0)
1270 && (permission && *permission == "android.permission.MANAGE_DOCUMENTS"));
1271 }
1272};
1273
1274/** Represents <receiver> elements. **/
1275class Receiver : public ManifestExtractor::Element {
1276 public:
1277 Receiver() = default;
1278 const std::string* permission = nullptr;
1279 bool has_component = false;
1280
1281 void Extract(xml::Element* element) override {
1282 permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
1283 }
1284};
1285
1286/**Represents <service> elements. **/
1287class Service : public ManifestExtractor::Element {
1288 public:
1289 Service() = default;
1290 const std::string* permission = nullptr;
1291 bool has_component = false;
1292
1293 void Extract(xml::Element* element) override {
1294 permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
1295 }
1296};
1297
1298/** Represents <uses-library> elements. **/
1299class UsesLibrary : public ManifestExtractor::Element {
1300 public:
1301 UsesLibrary() = default;
1302 std::string name;
1303 int required;
1304
1305 void Extract(xml::Element* element) override {
1306 auto parent_stack = extractor()->parent_stack();
1307 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1308 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1309 required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
1310 }
1311 }
1312
1313 void Print(text::Printer& printer) override {
1314 if (!name.empty()) {
1315 printer.Print(StringPrintf("uses-library%s:'%s'\n",
1316 (required == 0) ? "-not-required" : "", name.data()));
1317 }
1318 }
1319};
1320
1321/**
1322 * Represents <meta-data> elements. These tags are only printed when a flag is passed in to
1323 * explicitly enable meta data printing.
1324 **/
1325class MetaData : public ManifestExtractor::Element {
1326 public:
1327 MetaData() = default;
1328 std::string name;
1329 const std::string* value;
1330 const int* value_int;
1331 const std::string* resource;
1332 const int* resource_int;
1333
1334 void Extract(xml::Element* element) override {
1335 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1336 value = GetAttributeString(FindAttribute(element, VALUE_ATTR));
1337 value_int = GetAttributeInteger(FindAttribute(element, VALUE_ATTR));
1338 resource = GetAttributeString(FindAttribute(element, RESOURCE_ATTR));
1339 resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR));
1340 }
1341
1342 void Print(text::Printer& printer) override {
1343 if (extractor()->options_.include_meta_data && !name.empty()) {
1344 printer.Print(StringPrintf("meta-data: name='%s' ", name.data()));
1345 if (value) {
1346 printer.Print(StringPrintf("value='%s' ", value->data()));
1347 } else if (value_int) {
1348 printer.Print(StringPrintf("value='%d' ", *value_int));
1349 } else {
1350 if (resource) {
1351 printer.Print(StringPrintf("resource='%s' ", resource->data()));
1352 } else if (resource_int) {
1353 printer.Print(StringPrintf("resource='%d' ", *resource_int));
1354 }
1355 }
1356 printer.Print("\n");
1357 }
1358 }
1359};
1360
1361/**
1362 * Represents <action> elements. Detects the presence of certain activity, provider, receiver, and
1363 * service components.
1364 **/
1365class Action : public ManifestExtractor::Element {
1366 public:
1367 Action() = default;
1368 std::string component = "";
1369
1370 void Extract(xml::Element* element) override {
1371 auto parent_stack = extractor()->parent_stack();
1372 std::string action = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1373
1374 if (ElementCast<IntentFilter>(parent_stack[0])) {
1375 if (ElementCast<Activity>(parent_stack[1])) {
1376 // Detects the presence of a particular type of activity.
1377 Activity* activity = ElementCast<Activity>(parent_stack[1]);
1378 auto map = std::map<std::string, std::string>({
1379 { "android.intent.action.MAIN" , "main" },
1380 { "android.intent.action.VIDEO_CAMERA" , "camera" },
1381 { "android.intent.action.STILL_IMAGE_CAMERA_SECURE" , "camera-secure" },
1382 });
1383
1384 auto entry = map.find(action);
1385 if (entry != map.end()) {
1386 component = entry->second;
1387 activity->has_component_ = true;
1388 }
1389
1390 if (action == "android.intent.action.MAIN") {
1391 activity->has_main_action = true;
1392 }
1393
1394 } else if (ElementCast<Receiver>(parent_stack[1])) {
1395 // Detects the presence of a particular type of receiver. If the action requires a
1396 // permission, then the receiver element is checked for the permission.
1397 Receiver* receiver = ElementCast<Receiver>(parent_stack[1]);
1398 auto map = std::map<std::string, std::string>({
1399 { "android.appwidget.action.APPWIDGET_UPDATE" , "app-widget" },
1400 { "android.app.action.DEVICE_ADMIN_ENABLED" , "device-admin" },
1401 });
1402
1403 auto permissions = std::map<std::string, std::string>({
1404 { "android.app.action.DEVICE_ADMIN_ENABLED" , "android.permission.BIND_DEVICE_ADMIN" },
1405 });
1406
1407 auto entry = map.find(action);
1408 auto permission = permissions.find(action);
1409 if (entry != map.end() && (permission == permissions.end()
1410 || (receiver->permission && permission->second == *receiver->permission))) {
1411 receiver->has_component = true;
1412 component = entry->second;
1413 }
1414
1415 } else if (ElementCast<Service>(parent_stack[1])) {
1416 // Detects the presence of a particular type of service. If the action requires a
1417 // permission, then the service element is checked for the permission.
1418 Service* service = ElementCast<Service>(parent_stack[1]);
1419 auto map = std::map<std::string, std::string>({
1420 { "android.view.InputMethod" , "ime" },
1421 { "android.service.wallpaper.WallpaperService" , "wallpaper" },
1422 { "android.accessibilityservice.AccessibilityService" , "accessibility" },
1423 { "android.printservice.PrintService" , "print-service" },
1424 { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" , "host-apdu" },
1425 { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" , "offhost-apdu" },
1426 { "android.service.notification.NotificationListenerService" ,"notification-listener" },
1427 { "android.service.dreams.DreamService" , "dream" },
1428 });
1429
1430 auto permissions = std::map<std::string, std::string>({
1431 { "android.accessibilityservice.AccessibilityService" ,
1432 "android.permission.BIND_ACCESSIBILITY_SERVICE" },
1433 { "android.printservice.PrintService" , "android.permission.BIND_PRINT_SERVICE" },
1434 { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" ,
1435 "android.permission.BIND_NFC_SERVICE" },
1436 { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" ,
1437 "android.permission.BIND_NFC_SERVICE" },
1438 { "android.service.notification.NotificationListenerService" ,
1439 "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" },
1440 { "android.service.dreams.DreamService" , "android.permission.BIND_DREAM_SERVICE" },
1441 });
1442
1443 auto entry = map.find(action);
1444 auto permission = permissions.find(action);
1445 if (entry != map.end() && (permission == permissions.end()
1446 || (service->permission && permission->second == *service->permission))) {
1447 service->has_component= true;
1448 component = entry->second;
1449 }
1450
1451 } else if (ElementCast<Provider>(parent_stack[1])) {
1452 // Detects the presence of a particular type of receiver. If the provider requires a
1453 // permission, then the provider element is checked for the permission.
1454 // Detect whether this action
1455 Provider* provider = ElementCast<Provider>(parent_stack[1]);
1456 if (action == "android.content.action.DOCUMENTS_PROVIDER"
1457 && provider->has_required_saf_attributes) {
1458 component = "document-provider";
1459 }
1460 }
1461 }
1462
1463 // Represents a searchable interface
1464 if (action == "android.intent.action.SEARCH") {
1465 component = "search";
1466 }
1467 }
1468};
1469
1470/**
1471 * Represents <supports-input> elements. The element may have <input-type> elements nested within.
1472 **/
1473class SupportsInput : public ManifestExtractor::Element {
1474 public:
1475 SupportsInput() = default;
1476 std::vector<std::string> inputs;
1477
1478 void Print(text::Printer& printer) override {
1479 const size_t size = inputs.size();
1480 if (size > 0) {
1481 printer.Print("supports-input: '");
1482 for (size_t i = 0; i < size; i++) {
1483 printer.Print(StringPrintf("value='%s' ", inputs[i].data()));
1484 }
1485 printer.Print("\n");
1486 }
1487 }
1488};
1489
1490/** Represents <input-type> elements. **/
1491class InputType : public ManifestExtractor::Element {
1492 public:
1493 InputType() = default;
1494 void Extract(xml::Element* element) override {
1495 auto name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1496 auto parent_stack = extractor()->parent_stack();
1497
1498 // Add the input to the set of supported inputs
1499 if (name && ElementCast<SupportsInput>(parent_stack[0])) {
1500 SupportsInput* supports = ElementCast<SupportsInput>(parent_stack[0]);
1501 supports->inputs.push_back(*name);
1502 }
1503 }
1504};
1505
1506/** Represents <original-package> elements. **/
1507class OriginalPackage : public ManifestExtractor::Element {
1508 public:
1509 OriginalPackage() = default;
1510 const std::string* name = nullptr;
1511
1512 void Extract(xml::Element* element) override {
1513 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1514 }
1515
1516 void Print(text::Printer& printer) override {
1517 if (name) {
1518 printer.Print(StringPrintf("original-package:'%s'\n", name->data()));
1519 }
1520 }
1521};
1522
1523/** * Represents <package-verifier> elements. **/
1524class PackageVerifier : public ManifestExtractor::Element {
1525 public:
1526 PackageVerifier() = default;
1527 const std::string* name = nullptr;
1528 const std::string* public_key = nullptr;
1529
1530 void Extract(xml::Element* element) override {
1531 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1532 public_key = GetAttributeString(FindAttribute(element, PUBLIC_KEY_ATTR));
1533 }
1534
1535 void Print(text::Printer& printer) override {
1536 if (name && public_key) {
1537 printer.Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n",
1538 name->data(), public_key->data()));
1539 }
1540 }
1541};
1542
1543/** Represents <uses-package> elements. **/
1544class UsesPackage : public ManifestExtractor::Element {
1545 public:
1546 UsesPackage() = default;
1547 const std::string* name = nullptr;
1548
1549 void Extract(xml::Element* element) override {
1550 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1551 }
1552
1553 void Print(text::Printer& printer) override {
1554 if (name) {
1555 printer.Print(StringPrintf("uses-package:'%s'\n", name->data()));
1556 }
1557 }
1558};
1559
1560/** Represents <screen> elements found in <compatible-screens> elements. */
1561class Screen : public ManifestExtractor::Element {
1562 public:
1563 Screen() = default;
1564 const int32_t* size = nullptr;
1565 const int32_t* density = nullptr;
1566
1567 void Extract(xml::Element* element) override {
1568 size = GetAttributeInteger(FindAttribute(element, SCREEN_SIZE_ATTR));
1569 density = GetAttributeInteger(FindAttribute(element, SCREEN_DENSITY_ATTR));
1570 }
1571};
1572
1573/**
1574 * Represents <compatible-screens> elements. These elements have <screen> elements nested within
1575 * that each denote a supported screen size and screen density.
1576 **/
1577class CompatibleScreens : public ManifestExtractor::Element {
1578 public:
1579 CompatibleScreens() = default;
1580 void Print(text::Printer& printer) override {
1581 printer.Print("compatible-screens:");
1582
1583 bool first = true;
1584 ForEachChild(this, [&printer, &first](ManifestExtractor::Element* el){
1585 if (auto screen = ElementCast<Screen>(el)) {
1586 if (first) {
1587 first = false;
1588 } else {
1589 printer.Print(",");
1590 }
1591
1592 if (screen->size && screen->density) {
1593 printer.Print(StringPrintf("'%d/%d'", *screen->size, *screen->density));
1594 }
1595 }
1596 });
1597 printer.Print("\n");
1598 }
1599};
1600
1601/** Represents <supports-gl-texture> elements. **/
1602class SupportsGlTexture : public ManifestExtractor::Element {
1603 public:
1604 SupportsGlTexture() = default;
1605 const std::string* name = nullptr;
1606
1607 void Extract(xml::Element* element) override {
1608 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1609 }
1610
1611 void Print(text::Printer& printer) override {
1612 if (name) {
1613 printer.Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
1614 }
1615 }
1616};
1617
1618/** Recursively prints the extracted badging element. */
1619static void Print(ManifestExtractor::Element* el, text::Printer& printer) {
1620 el->Print(printer);
1621 for (auto &child : el->children()) {
1622 Print(child.get(), printer);
1623 }
1624}
1625
1626bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
1627 // Load the manifest
1628 std::unique_ptr<xml::XmlResource> doc = apk_->LoadXml("AndroidManifest.xml", diag);
1629 if (doc == nullptr) {
1630 diag->Error(DiagMessage() << "failed to find AndroidManifest.xml");
1631 return false;
1632 }
1633
1634 xml::Element* element = doc->root.get();
1635 if (element->name != "manifest") {
1636 diag->Error(DiagMessage() << "manifest does not start with <manifest> tag");
1637 return false;
1638 }
1639
1640 // Print only the <uses-permission>, <uses-permission-sdk23>, and <permission> elements if
1641 // printing only permission elements is requested
1642 if (options_.only_permissions) {
1643 std::unique_ptr<ManifestExtractor::Element> manifest_element =
1644 ManifestExtractor::Element::Inflate(this, element);
1645
1646 if (auto manifest = ElementCast<Manifest>(manifest_element.get())) {
1647 for (xml::Element* child : element->GetChildElements()) {
1648 if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
1649 || child->name == "permission") {
1650 auto permission_element = ManifestExtractor::Element::Inflate(this, child);
1651 manifest->AddChild(permission_element);
1652 }
1653 }
1654
1655 printer.Print(StringPrintf("package: %s\n", manifest->package.data()));
1656 ForEachChild(manifest, [&printer](ManifestExtractor::Element* el) -> void {
1657 el->Print(printer);
1658 });
1659
1660 return true;
1661 }
1662
1663 return false;
1664 }
1665
1666 // Collect information about the resource configurations
1667 if (apk_->GetResourceTable()) {
1668 for (auto &package : apk_->GetResourceTable()->packages) {
1669 for (auto &type : package->types) {
1670 for (auto &entry : type->entries) {
1671 for (auto &value : entry->values) {
1672 std::string locale_str = value->config.GetBcp47LanguageTag();
1673
1674 // Collect all the unique locales of the apk
1675 if (locales_.find(locale_str) == locales_.end()) {
1676 ConfigDescription config = ManifestExtractor::DummyConfig();
1677 config.setBcp47Locale(locale_str.data());
1678 locales_.insert(std::make_pair(locale_str, config));
1679 }
1680
1681 // Collect all the unique density of the apk
1682 uint16_t density = (value->config.density == 0) ? (uint16_t) 160
1683 : value->config.density;
1684 if (densities_.find(density) == densities_.end()) {
1685 ConfigDescription config = ManifestExtractor::DummyConfig();
1686 config.density = density;
1687 densities_.insert(std::make_pair(density, config));
1688 }
1689 }
1690 }
1691 }
1692 }
1693 }
1694
1695 // Extract badging information
1696 auto root = Visit(element);
1697
1698 // Print the elements in order seen
1699 Print(root.get(), printer);
1700
1701 /** Recursively checks the extracted elements for the specified permission. **/
1702 auto FindPermission = [&](ManifestExtractor::Element* root,
1703 const std::string& name) -> ManifestExtractor::Element* {
1704 return FindElement(root, [&](ManifestExtractor::Element* el) -> bool {
1705 if (UsesPermission* permission = ElementCast<UsesPermission>(el)) {
1706 return permission->name == name;
1707 }
1708 return false;
1709 });
1710 };
1711
1712 auto PrintPermission = [&printer](const std::string& name, const std::string& reason,
1713 int32_t max_sdk_version) -> void {
1714 auto permission = util::make_unique<UsesPermission>();
1715 permission->name = name;
1716 permission->maxSdkVersion = max_sdk_version;
1717 permission->Print(printer);
1718 permission->PrintImplied(printer, reason);
1719 };
1720
1721 // Implied permissions
1722 // Pre-1.6 implicitly granted permission compatibility logic
1723 CommonFeatureGroup* common_feature_group = GetCommonFeatureGroup();
1724 bool insert_write_external = false;
1725 auto write_external_permission = ElementCast<UsesPermission>(
1726 FindPermission(root.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
1727
1728 if (target_sdk() < 4) {
1729 if (!write_external_permission) {
1730 PrintPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
1731 insert_write_external = true;
1732 }
1733
1734 if (!FindPermission(root.get(), "android.permission.READ_PHONE_STATE")) {
1735 PrintPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
1736 }
1737 }
1738
1739 // If the application has requested WRITE_EXTERNAL_STORAGE, we will
1740 // force them to always take READ_EXTERNAL_STORAGE as well. We always
1741 // do this (regardless of target API version) because we can't have
1742 // an app with write permission but not read permission.
1743 auto read_external = FindPermission(root.get(), "android.permission.READ_EXTERNAL_STORAGE");
1744 if (!read_external && (insert_write_external || write_external_permission)) {
1745 PrintPermission("android.permission.READ_EXTERNAL_STORAGE",
1746 "requested WRITE_EXTERNAL_STORAGE",
1747 (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
1748 }
1749
1750 // Pre-JellyBean call log permission compatibility.
1751 if (target_sdk() < 16) {
1752 if (!FindPermission(root.get(), "android.permission.READ_CALL_LOG")
1753 && FindPermission(root.get(), "android.permission.READ_CONTACTS")) {
1754 PrintPermission("android.permission.READ_CALL_LOG",
1755 "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
1756 }
1757
1758 if (!FindPermission(root.get(), "android.permission.WRITE_CALL_LOG")
1759 && FindPermission(root.get(), "android.permission.WRITE_CONTACTS")) {
1760 PrintPermission("android.permission.WRITE_CALL_LOG",
1761 "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
1762 }
1763 }
1764
1765 // If the app hasn't declared the touchscreen as a feature requirement (either
1766 // directly or implied, required or not), then the faketouch feature is implied.
1767 if (!common_feature_group->HasFeature("android.hardware.touchscreen")) {
1768 common_feature_group->addImpliedFeature("android.hardware.faketouch",
1769 "default feature for all apps", false);
1770 }
1771
1772 // Only print the common feature group if no feature group is defined
1773 std::vector<FeatureGroup*> feature_groups;
1774 ForEachChild(root.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
1775 if (auto feature_group = ElementCast<FeatureGroup>(el)) {
1776 feature_groups.push_back(feature_group);
1777 }
1778 });
1779
1780 if (feature_groups.empty()) {
1781 common_feature_group->PrintGroup(printer);
1782 } else {
1783 // Merge the common feature group into the feature group
1784 for (auto& feature_group : feature_groups) {
1785 feature_group->open_gles_version = std::max(feature_group->open_gles_version,
1786 common_feature_group->open_gles_version);
1787 feature_group->Merge(common_feature_group);
1788 feature_group->PrintGroup(printer);
1789 }
1790 };
1791
1792 // Collect the component types of the application
1793 std::set<std::string> components;
1794 ForEachChild(root.get(), [&components](ManifestExtractor::Element* el) -> void {
1795 if (ElementCast<Action>(el)) {
1796 auto action = ElementCast<Action>(el);
1797 if (!action->component.empty()) {
1798 components.insert(action->component);
1799 return;
1800 }
1801 }
1802
1803 if (ElementCast<Category>(el)) {
1804 auto category = ElementCast<Category>(el);
1805 if (!category->component.empty()) {
1806 components.insert(category->component);
1807 return;
1808 }
1809 }
1810 });
1811
1812 // Check for the payment component
1813 auto apk = apk_;
1814 ForEachChild(root.get(), [&apk, &components, &diag](ManifestExtractor::Element* el) -> void {
1815 if (auto service = ElementCast<Service>(el)) {
1816 auto host_apdu_action = ElementCast<Action>(FindElement(service,
1817 [&](ManifestExtractor::Element* el) -> bool {
1818 if (auto action = ElementCast<Action>(el)) {
1819 return (action->component == "host-apdu");
1820 }
1821 return false;
1822 }));
1823
1824 auto offhost_apdu_action = ElementCast<Action>(FindElement(service,
1825 [&](ManifestExtractor::Element* el) -> bool {
1826 if (auto action = ElementCast<Action>(el)) {
1827 return (action->component == "offhost-apdu");
1828 }
1829 return false;
1830 }));
1831
1832 ForEachChild(service, [&apk, &components, &diag, &host_apdu_action,
1833 &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
1834 if (auto meta_data = ElementCast<MetaData>(el)) {
1835 if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" && host_apdu_action)
1836 || (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service"
1837 && offhost_apdu_action)) {
1838
1839 // Attempt to load the resource file
1840 if (!meta_data->resource) {
1841 return;
1842 }
1843 auto resource = apk->LoadXml(*meta_data->resource, diag);
1844 if (!resource) {
1845 return;
1846 }
1847
1848 // Look for the payment category on an <aid-group> element
1849 auto& root = resource.get()->root;
1850 if ((host_apdu_action && root->name == "host-apdu-service")
1851 || (offhost_apdu_action && root->name == "offhost-apdu-service")) {
1852
1853 for (auto& child : root->GetChildElements()) {
1854 if (child->name == "aid-group") {
1855 auto category = FindAttribute(child, CATEGORY_ATTR);
1856 if (category && category->value == "payment") {
1857 components.insert("payment");
1858 return;
1859 }
1860 }
1861 }
1862 }
1863 }
1864 }
1865 });
1866 }
1867 });
1868
1869 // Print the components types if they are present
1870 auto PrintComponent = [&components, &printer](const std::string& component) -> void {
1871 if (components.find(component) != components.end()) {
1872 printer.Print(StringPrintf("provides-component:'%s'\n", component.data()));
1873 }
1874 };
1875
1876 PrintComponent("app-widget");
1877 PrintComponent("device-admin");
1878 PrintComponent("ime");
1879 PrintComponent("wallpaper");
1880 PrintComponent("accessibility");
1881 PrintComponent("print-service");
1882 PrintComponent("payment");
1883 PrintComponent("search");
1884 PrintComponent("document-provider");
1885 PrintComponent("launcher");
1886 PrintComponent("notification-listener");
1887 PrintComponent("dream");
1888 PrintComponent("camera");
1889 PrintComponent("camera-secure");
1890
1891 // Print presence of main activity
1892 if (components.find("main") != components.end()) {
1893 printer.Print("main\n");
1894 }
1895
1896 // Print presence of activities, recivers, and services with no special components
1897 FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
1898 if (auto activity = ElementCast<Activity>(el)) {
1899 if (!activity->has_component_) {
1900 printer.Print("other-activities\n");
1901 return true;
1902 }
1903 }
1904 return false;
1905 });
1906
1907 FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
1908 if (auto receiver = ElementCast<Receiver>(el)) {
1909 if (!receiver->has_component) {
1910 printer.Print("other-receivers\n");
1911 return true;
1912 }
1913 }
1914 return false;
1915 });
1916
1917 FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
1918 if (auto service = ElementCast<Service>(el)) {
1919 if (!service->has_component) {
1920 printer.Print("other-services\n");
1921 return true;
1922 }
1923 }
1924 return false;
1925 });
1926
1927 // Print the supported screens
1928 SupportsScreen* screen = ElementCast<SupportsScreen>(FindElement(root.get(),
1929 [&](ManifestExtractor::Element* el) -> bool {
1930 return ElementCast<SupportsScreen>(el) != nullptr;
1931 }));
1932
1933 if (screen) {
1934 screen->PrintScreens(printer, target_sdk_);
1935 } else {
1936 // Print the default supported screens
1937 SupportsScreen default_screens;
1938 default_screens.PrintScreens(printer, target_sdk_);
1939 }
1940
1941 // Print all the unique locales of the apk
1942 printer.Print("locales:");
1943 for (auto& config : locales_) {
1944 if (config.first.empty()) {
1945 printer.Print(" '--_--'");
1946 } else {
1947 printer.Print(StringPrintf(" '%s'", config.first.data()));
1948 }
1949 }
1950 printer.Print("\n");
1951
1952 // Print all the densities locales of the apk
1953 printer.Print("densities:");
1954 for (auto& config : densities_) {
1955 printer.Print(StringPrintf(" '%d'", config.first));
1956 }
1957 printer.Print("\n");
1958
1959 // Print the supported architectures of the app
1960 std::set<std::string> architectures;
1961 auto it = apk_->GetFileCollection()->Iterator();
1962 while (it->HasNext()) {
1963 auto file_path = it->Next()->GetSource().path;
1964
1965
1966 size_t pos = file_path.find("lib/");
1967 if (pos != std::string::npos) {
1968 file_path = file_path.substr(pos + 4);
1969 pos = file_path.find("/");
1970 if (pos != std::string::npos) {
1971 file_path = file_path.substr(0, pos);
1972 }
1973
1974 architectures.insert(file_path);
1975 }
1976 }
1977
1978 // Determine if the application has multiArch supports
1979 auto has_multi_arch = FindElement(root.get(), [&](ManifestExtractor::Element* el) -> bool {
1980 if (auto application = ElementCast<Application>(el)) {
1981 return application->has_multi_arch;
1982 }
1983 return false;
1984 });
1985
1986 bool output_alt_native_code = false;
1987 // A multiArch package is one that contains 64-bit and
1988 // 32-bit versions of native code and expects 3rd-party
1989 // apps to load these native code libraries. Since most
1990 // 64-bit systems also support 32-bit apps, the apps
1991 // loading this multiArch package's code may be either
1992 if (has_multi_arch) {
1993 // If this is a multiArch package, report the 64-bit
1994 // version only. Then as a separate entry, report the
1995 // rest.
1996 //
1997 // If we report the 32-bit architecture, this APK will
1998 // be installed on a 32-bit device, causing a large waste
1999 // of bandwidth and disk space. This assumes that
2000 // the developer of the multiArch package has also
2001 // made a version that is 32-bit only.
2002 const std::string kIntel64 = "x86_64";
2003 const std::string kArm64 = "arm64-v8a";
2004
2005 auto arch = architectures.find(kIntel64);
2006 if (arch == architectures.end()) {
2007 arch = architectures.find(kArm64);
2008 }
2009
2010 if (arch != architectures.end()) {
2011 printer.Print(StringPrintf("native-code: '%s'\n", arch->data()));
2012 architectures.erase(arch);
2013 output_alt_native_code = true;
2014 }
2015 }
2016
2017 if (architectures.size() > 0) {
2018 if (output_alt_native_code) {
2019 printer.Print("alt-");
2020 }
2021 printer.Print("native-code:");
2022 for (auto& arch : architectures) {
2023 printer.Print(StringPrintf(" '%s'", arch.data()));
2024 }
2025 printer.Print("\n");
2026 }
2027
2028 return true;
2029}
2030
2031/**
2032 * Returns the element casted to the type if the element is of that type. Otherwise, returns a null
2033 * pointer.
2034 **/
2035template<typename T>
2036T* ElementCast(ManifestExtractor::Element* element) {
2037 if (element == nullptr) {
2038 return nullptr;
2039 }
2040
2041 const std::unordered_map<std::string, bool> kTagCheck = {
2042 {"action", std::is_base_of<Action, T>::value},
2043 {"activity", std::is_base_of<Activity, T>::value},
2044 {"application", std::is_base_of<Application, T>::value},
2045 {"category", std::is_base_of<Category, T>::value},
2046 {"compatible-screens", std::is_base_of<CompatibleScreens, T>::value},
2047 {"feature-group", std::is_base_of<FeatureGroup, T>::value},
2048 {"input-type", std::is_base_of<InputType, T>::value},
2049 {"intent-filter", std::is_base_of<IntentFilter, T>::value},
2050 {"meta-data", std::is_base_of<MetaData, T>::value},
2051 {"manifest", std::is_base_of<Manifest, T>::value},
2052 {"original-package", std::is_base_of<OriginalPackage, T>::value},
2053 {"package-verifier", std::is_base_of<PackageVerifier, T>::value},
2054 {"permission", std::is_base_of<Permission, T>::value},
2055 {"provider", std::is_base_of<Provider, T>::value},
2056 {"receiver", std::is_base_of<Receiver, T>::value},
2057 {"screen", std::is_base_of<Screen, T>::value},
2058 {"service", std::is_base_of<Service, T>::value},
2059 {"supports-gl-texture", std::is_base_of<SupportsGlTexture, T>::value},
2060 {"supports-input", std::is_base_of<SupportsInput, T>::value},
2061 {"supports-screens", std::is_base_of<SupportsScreen, T>::value},
2062 {"uses-configuration", std::is_base_of<UsesConfiguarion, T>::value},
2063 {"uses-feature", std::is_base_of<UsesFeature, T>::value},
2064 {"uses-permission", std::is_base_of<UsesPermission, T>::value},
2065 {"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
2066 {"uses-library", std::is_base_of<UsesLibrary, T>::value},
2067 {"uses-package", std::is_base_of<UsesPackage, T>::value},
2068 {"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
2069 };
2070
2071 auto check = kTagCheck.find(element->tag());
2072 if (check != kTagCheck.end() && check->second) {
2073 return static_cast<T*>(element);
2074 }
2075 return nullptr;
2076}
2077
2078template<typename T>
2079std::unique_ptr<T> CreateType() {
2080 return std::move(util::make_unique<T>());
2081}
2082
2083std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
2084 ManifestExtractor* extractor, xml::Element* el) {
2085 const std::unordered_map<std::string,
2086 std::function<std::unique_ptr<ManifestExtractor::Element>()>>
2087 kTagCheck = {
2088 {"action", &CreateType<Action>},
2089 {"activity", &CreateType<Activity>},
2090 {"application", &CreateType<Application>},
2091 {"category", &CreateType<Category>},
2092 {"compatible-screens", &CreateType<CompatibleScreens>},
2093 {"feature-group", &CreateType<FeatureGroup>},
2094 {"input-type", &CreateType<InputType>},
2095 {"intent-filter",&CreateType<IntentFilter>},
2096 {"manifest", &CreateType<Manifest>},
2097 {"meta-data", &CreateType<MetaData>},
2098 {"original-package", &CreateType<OriginalPackage>},
2099 {"package-verifier", &CreateType<PackageVerifier>},
2100 {"permission", &CreateType<Permission>},
2101 {"provider", &CreateType<Provider>},
2102 {"receiver", &CreateType<Receiver>},
2103 {"screen", &CreateType<Screen>},
2104 {"service", &CreateType<Service>},
2105 {"supports-gl-texture", &CreateType<SupportsGlTexture>},
2106 {"supports-input", &CreateType<SupportsInput>},
2107 {"supports-screens", &CreateType<SupportsScreen>},
2108 {"uses-configuration", &CreateType<UsesConfiguarion>},
2109 {"uses-feature", &CreateType<UsesFeature>},
2110 {"uses-permission", &CreateType<UsesPermission>},
2111 {"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
2112 {"uses-library", &CreateType<UsesLibrary>},
2113 {"uses-package", &CreateType<UsesPackage>},
2114 {"uses-sdk", &CreateType<UsesSdkBadging>},
2115 };
2116
2117 // Attempt to map the xml tag to a element inflater
2118 std::unique_ptr<ManifestExtractor::Element> element;
2119 auto check = kTagCheck.find(el->name);
2120 if (check != kTagCheck.end()) {
2121 element = check->second();
2122 } else {
2123 element = util::make_unique<ManifestExtractor::Element>();
2124 }
2125
2126 element->extractor_ = extractor;
2127 element->tag_ = el->name;
2128 element->Extract(el);
2129 return element;
2130}
2131
2132std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(xml::Element* el) {
2133 auto element = ManifestExtractor::Element::Inflate(this, el);
2134 parent_stack_.insert(parent_stack_.begin(), element.get());
2135
2136 // Process the element and recursively visit the children
2137 for (xml::Element* child : el->GetChildElements()) {
2138 auto v = Visit(child);
2139 element->AddChild(v);
2140 }
2141
2142 parent_stack_.erase(parent_stack_.begin());
2143 return element;
2144}
2145
2146// Use a smaller buffer so that there is less latency for dumping to stdout.
2147constexpr size_t kStdOutBufferSize = 1024u;
2148
2149int DumpBadgingCommand::Action(const std::vector<std::string>& args) {
2150 if (args.size() < 1) {
2151 diag_->Error(DiagMessage() << "No dump apk specified.");
2152 return 1;
2153 }
2154
2155 ManifestExtractor::Options options;
2156 options.include_meta_data = include_metadata_;
2157
2158 io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
2159 text::Printer printer(&fout);
2160 for (auto apk : args) {
2161 auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
2162 if (!loaded_apk) {
2163 return 1;
2164 }
2165
2166 ManifestExtractor extractor(loaded_apk.get(), options);
2167 extractor.Dump(printer, diag_);
2168 }
2169
2170 return 0;
2171}
2172
2173int DumpPermissionsCommand::Action(const std::vector<std::string>& args) {
2174 if (args.size() < 1) {
2175 diag_->Error(DiagMessage() << "No dump apk specified.");
2176 return 1;
2177 }
2178
2179 ManifestExtractor::Options options;
2180 options.only_permissions = true;
2181
2182 io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
2183 text::Printer printer(&fout);
2184 for (auto apk : args) {
2185 auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
2186 if (!loaded_apk) {
2187 return 1;
2188 }
2189
2190 ManifestExtractor extractor(loaded_apk.get(), options);
2191 extractor.Dump(printer, diag_);
2192 }
2193
2194 return 0;
2195}
2196
2197} // namespace aapt