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