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