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