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