blob: 11a4074cd3cdee294debabadf23a63b30bdd33b1 [file] [log] [blame]
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "DumpManifest.h"
18
Dianne Hackborn813d7502018-10-02 16:59:46 -070019#include <algorithm>
20
Ryan Mitchellfc225b22018-08-21 14:52:51 -070021#include "LoadedApk.h"
22#include "SdkConstants.h"
23#include "ValueVisitor.h"
24#include "io/File.h"
25#include "io/FileStream.h"
26#include "process/IResourceTableConsumer.h"
27#include "xml/XmlDom.h"
28
Mårten Kongstad24c9aa62018-06-20 08:46:41 +020029#include "androidfw/ConfigDescription.h"
30
Ryan Mitchellfc225b22018-08-21 14:52:51 -070031using ::android::base::StringPrintf;
Mårten Kongstad24c9aa62018-06-20 08:46:41 +020032using ::android::ConfigDescription;
Ryan Mitchellfc225b22018-08-21 14:52:51 -070033
34namespace aapt {
35
36/**
37 * These are attribute resource constants for the platform, as found in android.R.attr.
38 */
39enum {
40 LABEL_ATTR = 0x01010001,
41 ICON_ATTR = 0x01010002,
42 NAME_ATTR = 0x01010003,
43 PERMISSION_ATTR = 0x01010006,
44 EXPORTED_ATTR = 0x01010010,
45 GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
46 RESOURCE_ATTR = 0x01010025,
47 DEBUGGABLE_ATTR = 0x0101000f,
48 VALUE_ATTR = 0x01010024,
49 VERSION_CODE_ATTR = 0x0101021b,
50 VERSION_NAME_ATTR = 0x0101021c,
51 SCREEN_ORIENTATION_ATTR = 0x0101001e,
52 MIN_SDK_VERSION_ATTR = 0x0101020c,
53 MAX_SDK_VERSION_ATTR = 0x01010271,
54 REQ_TOUCH_SCREEN_ATTR = 0x01010227,
55 REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
56 REQ_HARD_KEYBOARD_ATTR = 0x01010229,
57 REQ_NAVIGATION_ATTR = 0x0101022a,
58 REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
59 TARGET_SDK_VERSION_ATTR = 0x01010270,
60 TEST_ONLY_ATTR = 0x01010272,
61 ANY_DENSITY_ATTR = 0x0101026c,
62 GL_ES_VERSION_ATTR = 0x01010281,
63 SMALL_SCREEN_ATTR = 0x01010284,
64 NORMAL_SCREEN_ATTR = 0x01010285,
65 LARGE_SCREEN_ATTR = 0x01010286,
66 XLARGE_SCREEN_ATTR = 0x010102bf,
67 REQUIRED_ATTR = 0x0101028e,
68 INSTALL_LOCATION_ATTR = 0x010102b7,
69 SCREEN_SIZE_ATTR = 0x010102ca,
70 SCREEN_DENSITY_ATTR = 0x010102cb,
71 REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
72 COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
73 LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
74 PUBLIC_KEY_ATTR = 0x010103a6,
75 CATEGORY_ATTR = 0x010103e8,
76 BANNER_ATTR = 0x10103f2,
77 ISGAME_ATTR = 0x10103f4,
Dianne Hackborn813d7502018-10-02 16:59:46 -070078 VERSION_ATTR = 0x01010519,
79 CERT_DIGEST_ATTR = 0x01010548,
Ryan Mitchellfc225b22018-08-21 14:52:51 -070080 REQUIRED_FEATURE_ATTR = 0x1010557,
81 REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
82 COMPILE_SDK_VERSION_ATTR = 0x01010572,
83 COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573,
Dianne Hackborn813d7502018-10-02 16:59:46 -070084 VERSION_MAJOR_ATTR = 0x01010577,
85 PACKAGE_TYPE_ATTR = 0x01010587,
Ryan Mitchellfc225b22018-08-21 14:52:51 -070086};
87
88const std::string& kAndroidNamespace = "http://schemas.android.com/apk/res/android";
89
90/** Retrieves the attribute of the element with the specified attribute resource id. */
91static xml::Attribute* FindAttribute(xml::Element *el, uint32_t resd_id) {
92 for (auto& a : el->attributes) {
93 if (a.compiled_attribute && a.compiled_attribute.value().id) {
94 if (a.compiled_attribute.value().id.value() == resd_id) {
95 return std::move(&a);
96 }
97 }
98 }
99 return nullptr;
100}
101
102/** Retrieves the attribute of the element that has the specified namespace and attribute name. */
103static xml::Attribute* FindAttribute(xml::Element *el, const std::string &package,
104 const std::string &name) {
105 return el->FindAttribute(package, name);
106}
107
108class CommonFeatureGroup;
109
110class ManifestExtractor {
111 public:
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700112
Ryan Mitchell214846d2018-09-19 16:57:01 -0700113 explicit ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options)
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700114 : apk_(apk), options_(options) { }
115
116 class Element {
117 public:
118 Element() = default;
119 virtual ~Element() = default;
120
121 static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
122
123 /** Writes out the extracted contents of the element. */
Ryan Mitchell214846d2018-09-19 16:57:01 -0700124 virtual void Print(text::Printer* printer) { }
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700125
126 /** Adds an element to the list of children of the element. */
127 void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); }
128
129 /** Retrieves the list of children of the element. */
130 const std::vector<std::unique_ptr<Element>>& children() const {
131 return children_;
132 }
133
134 /** Retrieves the extracted xml element tag. */
135 const std::string tag() const {
136 return tag_;
137 }
138
139 protected:
140 ManifestExtractor* extractor() const {
141 return extractor_;
142 }
143
144 /** Retrieves and stores the information extracted from the xml element. */
145 virtual void Extract(xml::Element* el) { }
146
147 /*
148 * Retrieves a configuration value of the resource entry that best matches the specified
149 * configuration.
150 */
151 static Value* BestConfigValue(ResourceEntry* entry,
152 const ConfigDescription& match) {
153 if (!entry) {
154 return nullptr;
155 }
156
157 // Determine the config that best matches the desired config
158 ResourceConfigValue* best_value = nullptr;
159 for (auto& value : entry->values) {
160 if (!value->config.match(match)) {
161 continue;
162 }
163
164 if (best_value != nullptr) {
165 if (!value->config.isBetterThan(best_value->config, &match)) {
166 if (value->config.compare(best_value->config) != 0) {
167 continue;
168 }
169 }
170 }
171
172 best_value = value.get();
173 }
174
175 // The entry has no values
176 if (!best_value) {
177 return nullptr;
178 }
179
180 return best_value->value.get();
181 }
182
183 /** Retrieves the resource assigned to the specified resource id if one exists. */
184 Value* FindValueById(const ResourceTable* table, const ResourceId& res_id,
185 const ConfigDescription& config = DummyConfig()) {
186 if (table) {
187 for (auto& package : table->packages) {
188 if (package->id && package->id.value() == res_id.package_id()) {
189 for (auto& type : package->types) {
190 if (type->id && type->id.value() == res_id.type_id()) {
191 for (auto& entry : type->entries) {
192 if (entry->id && entry->id.value() == res_id.entry_id()) {
193 if (auto value = BestConfigValue(entry.get(), config)) {
194 return value;
195 }
196 }
197 }
198 }
199 }
200 }
201 }
202 }
203 return nullptr;
204 }
205
206 /** Attempts to resolve the reference to a non-reference value. */
207 Value* ResolveReference(Reference* ref, const ConfigDescription& config = DummyConfig()) {
208 const int kMaxIterations = 40;
209 int i = 0;
210 while (ref && ref->id && i++ < kMaxIterations) {
211 auto table = extractor_->apk_->GetResourceTable();
212 if (auto value = FindValueById(table, ref->id.value(), config)) {
213 if (ValueCast<Reference>(value)) {
214 ref = ValueCast<Reference>(value);
215 } else {
216 return value;
217 }
218 }
219 }
220 return nullptr;
221 }
222
223 /**
224 * Retrieves the integer value of the attribute . If the value of the attribute is a reference,
225 * this will attempt to resolve the reference to an integer value.
226 **/
227 int32_t* GetAttributeInteger(xml::Attribute* attr,
228 const ConfigDescription& config = DummyConfig()) {
229 if (attr != nullptr) {
230 if (attr->compiled_value) {
231 // Resolve references using the dummy configuration
232 Value* value = attr->compiled_value.get();
233 if (ValueCast<Reference>(value)) {
234 value = ResolveReference(ValueCast<Reference>(value), config);
235 } else {
236 value = attr->compiled_value.get();
237 }
238 // Retrieve the integer data if possible
239 if (value != nullptr) {
240 if (BinaryPrimitive* intValue = ValueCast<BinaryPrimitive>(value)) {
241 return (int32_t*) &intValue->value.data;
242 }
243 }
244 }
245 }
246 return nullptr;
247 }
248
249 /**
250 * A version of GetAttributeInteger that returns a default integer if the attribute does not
251 * exist or cannot be resolved to an integer value.
252 **/
253 int32_t GetAttributeIntegerDefault(xml::Attribute* attr, int32_t def,
254 const ConfigDescription& config = DummyConfig()) {
255 auto value = GetAttributeInteger(attr, config);
256 if (value) {
257 return *value;
258 }
259 return def;
260 }
261
262 /**
263 * Retrieves the string value of the attribute. If the value of the attribute is a reference,
264 * this will attempt to resolve the reference to a string value.
265 **/
266 const std::string* GetAttributeString(xml::Attribute* attr,
267 const ConfigDescription& config = DummyConfig()) {
268 if (attr != nullptr) {
269 if (attr->compiled_value) {
270 // Resolve references using the dummy configuration
271 Value* value = attr->compiled_value.get();
272 if (ValueCast<Reference>(value)) {
273 value = ResolveReference(ValueCast<Reference>(value), config);
274 } else {
275 value = attr->compiled_value.get();
276 }
277
278 // Retrieve the string data of the value if possible
279 if (value != nullptr) {
280 if (String* intValue = ValueCast<String>(value)) {
281 return &(*intValue->value);
282 } else if (RawString* rawValue = ValueCast<RawString>(value)) {
283 return &(*rawValue->value);
284 } else if (FileReference* strValue = ValueCast<FileReference>(value)) {
285 return &(*strValue->path);
286 }
287 }
288 }
289 return &attr->value;
290 }
291 return nullptr;
292 }
293
294 /**
295 * A version of GetAttributeString that returns a default string if the attribute does not
296 * exist or cannot be resolved to an string value.
297 **/
298 std::string GetAttributeStringDefault(xml::Attribute* attr, std::string def,
299 const ConfigDescription& config = DummyConfig()) {
300 auto value = GetAttributeString(attr, config);
301 if (value) {
302 return *value;
303 }
304 return def;
305 }
306
307 private:
308 ManifestExtractor* extractor_;
309 std::vector<std::unique_ptr<Element>> children_;
310 std::string tag_;
311 };
312
313 friend Element;
314
315 /** Creates a default configuration used to retrieve resources. */
316 static ConfigDescription DummyConfig() {
317 ConfigDescription config;
318 config.orientation = android::ResTable_config::ORIENTATION_PORT;
319 config.density = android::ResTable_config::DENSITY_MEDIUM;
320 config.sdkVersion = 10000; // Very high.
321 config.screenWidthDp = 320;
322 config.screenHeightDp = 480;
323 config.smallestScreenWidthDp = 320;
324 config.screenLayout |= android::ResTable_config::SCREENSIZE_NORMAL;
325 return config;
326 }
327
Ryan Mitchell214846d2018-09-19 16:57:01 -0700328 bool Dump(text::Printer* printer, IDiagnostics* diag);
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700329
330 /** Recursively visit the xml element tree and return a processed badging element tree. */
331 std::unique_ptr<Element> Visit(xml::Element* element);
332
333 /** Raises the target sdk value if the min target is greater than the current target. */
334 void RaiseTargetSdk(int32_t min_target) {
335 if (min_target > target_sdk_) {
336 target_sdk_ = min_target;
337 }
338 }
339
340 /**
341 * Retrieves the default feature group that features are added into when <uses-feature>
342 * are not in a <feature-group> element.
343 **/
344 CommonFeatureGroup* GetCommonFeatureGroup() {
345 return commonFeatureGroup_.get();
346 }
347
348 /**
349 * Retrieves a mapping of density values to Configurations for retrieving resources that would be
350 * used for that density setting.
351 **/
352 const std::map<uint16_t, ConfigDescription> densities() const {
353 return densities_;
354 }
355
356 /**
357 * Retrieves a mapping of locale BCP 47 strings to Configurations for retrieving resources that
358 * would be used for that locale setting.
359 **/
360 const std::map<std::string, ConfigDescription> locales() const {
361 return locales_;
362 }
363
364 /** Retrieves the current stack of parent during data extraction. */
365 const std::vector<Element*> parent_stack() const {
366 return parent_stack_;
367 }
368
369 int32_t target_sdk() const {
370 return target_sdk_;
371 }
372
373 LoadedApk* const apk_;
Ryan Mitchell214846d2018-09-19 16:57:01 -0700374 DumpManifestOptions& options_;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700375
376 private:
377 std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
378 std::map<std::string, ConfigDescription> locales_;
379 std::map<uint16_t, ConfigDescription> densities_;
380 std::vector<Element*> parent_stack_;
381 int32_t target_sdk_ = 0;
382};
383
384template<typename T> T* ElementCast(ManifestExtractor::Element* element);
385
386/** Recurs through the children of the specified root in depth-first order. */
387static void ForEachChild(ManifestExtractor::Element* root,
388 std::function<void(ManifestExtractor::Element*)> f) {
389 for (auto& child : root->children()) {
390 f(child.get());
391 ForEachChild(child.get(), f);
392 }
393}
394
395/**
396 * Checks the element and its recursive children for an element that makes the specified
397 * conditional function return true. Returns the first element that makes the conditional function
398 * return true.
399 **/
400static ManifestExtractor::Element* FindElement(ManifestExtractor::Element* root,
401 std::function<bool(ManifestExtractor::Element*)> f) {
402 if (f(root)) {
403 return root;
404 }
405 for (auto& child : root->children()) {
406 if (auto b2 = FindElement(child.get(), f)) {
407 return b2;
408 }
409 }
410 return nullptr;
411}
412
413/** Represents the <manifest> elements **/
414class Manifest : public ManifestExtractor::Element {
415 public:
416 Manifest() = default;
417 std::string package;
418 int32_t versionCode;
419 std::string versionName;
420 const std::string* split = nullptr;
421 const std::string* platformVersionName = nullptr;
422 const std::string* platformVersionCode = nullptr;
423 const int32_t* compilesdkVersion = nullptr;
424 const std::string* compilesdkVersionCodename = nullptr;
425 const int32_t* installLocation = nullptr;
426
427 void Extract(xml::Element* manifest) override {
428 package = GetAttributeStringDefault(FindAttribute(manifest, {}, "package"), "");
429 versionCode = GetAttributeIntegerDefault(FindAttribute(manifest, VERSION_CODE_ATTR), 0);
430 versionName = GetAttributeStringDefault(FindAttribute(manifest, VERSION_NAME_ATTR), "");
431 split = GetAttributeString(FindAttribute(manifest, {}, "split"));
432
433 // Extract the platform build info
434 platformVersionName = GetAttributeString(FindAttribute(manifest, {},
435 "platformBuildVersionName"));
436 platformVersionCode = GetAttributeString(FindAttribute(manifest, {},
437 "platformBuildVersionCode"));
438
439 // Extract the compile sdk info
440 compilesdkVersion = GetAttributeInteger(FindAttribute(manifest, COMPILE_SDK_VERSION_ATTR));
441 compilesdkVersionCodename = GetAttributeString(
442 FindAttribute(manifest, COMPILE_SDK_VERSION_CODENAME_ATTR));
443 installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR));
444 }
445
Ryan Mitchell214846d2018-09-19 16:57:01 -0700446 void Print(text::Printer* printer) override {
447 printer->Print(StringPrintf("package: name='%s' ", package.data()));
448 printer->Print(StringPrintf("versionCode='%s' ",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700449 (versionCode > 0) ? std::to_string(versionCode).data() : ""));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700450 printer->Print(StringPrintf("versionName='%s'", versionName.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700451
452 if (split) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700453 printer->Print(StringPrintf(" split='%s'", split->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700454 }
455 if (platformVersionName) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700456 printer->Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700457 }
458 if (platformVersionCode) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700459 printer->Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700460 }
461 if (compilesdkVersion) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700462 printer->Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700463 }
464 if (compilesdkVersionCodename) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700465 printer->Print(StringPrintf(" compileSdkVersionCodename='%s'",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700466 compilesdkVersionCodename->data()));
467 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700468 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700469
470 if (installLocation) {
471 switch (*installLocation) {
472 case 0:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700473 printer->Print("install-location:'auto'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700474 break;
475 case 1:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700476 printer->Print("install-location:'internalOnly'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700477 break;
478 case 2:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700479 printer->Print("install-location:'preferExternal'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700480 break;
481 default:
482 break;
483 }
484 }
485 }
486};
487
488/** Represents <application> elements. **/
489class Application : public ManifestExtractor::Element {
490 public:
491 Application() = default;
492 std::string label;
493 std::string icon;
494 std::string banner;
495 int32_t is_game;
496 int32_t debuggable;
497 int32_t test_only;
498 bool has_multi_arch;
499
500 /** Mapping from locales to app names. */
501 std::map<std::string, std::string> locale_labels;
502
503 /** Mapping from densities to app icons. */
504 std::map<uint16_t, std::string> density_icons;
505
506 void Extract(xml::Element* element) override {
507 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
508 icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
509 test_only = GetAttributeIntegerDefault(FindAttribute(element, TEST_ONLY_ATTR), 0);
510 banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
511 is_game = GetAttributeIntegerDefault(FindAttribute(element, ISGAME_ATTR), 0);
512 debuggable = GetAttributeIntegerDefault(FindAttribute(element, DEBUGGABLE_ATTR), 0);
513
514 // We must search by name because the multiArch flag hasn't been API
515 // frozen yet.
516 has_multi_arch = (GetAttributeIntegerDefault(
517 FindAttribute(element, kAndroidNamespace, "multiArch"), 0) != 0);
518
519 // Retrieve the app names for every locale the app supports
520 auto attr = FindAttribute(element, LABEL_ATTR);
521 for (auto& config : extractor()->locales()) {
522 if (auto label = GetAttributeString(attr, config.second)) {
523 if (label) {
524 locale_labels.insert(std::make_pair(config.first, *label));
525 }
526 }
527 }
528
529 // Retrieve the icons for the densities the app supports
530 attr = FindAttribute(element, ICON_ATTR);
531 for (auto& config : extractor()->densities()) {
532 if (auto resource = GetAttributeString(attr, config.second)) {
533 if (resource) {
534 density_icons.insert(std::make_pair(config.first, *resource));
535 }
536 }
537 }
538 }
539
Ryan Mitchell214846d2018-09-19 16:57:01 -0700540 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700541 // Print the labels for every locale
542 for (auto p : locale_labels) {
543 if (p.first.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700544 printer->Print(StringPrintf("application-label:'%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700545 android::ResTable::normalizeForOutput(p.second.data())
546 .c_str()));
547 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700548 printer->Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(),
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700549 android::ResTable::normalizeForOutput(p.second.data())
550 .c_str()));
551 }
552 }
553
554 // Print the icon paths for every density
555 for (auto p : density_icons) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700556 printer->Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700557 }
558
559 // Print the application info
Ryan Mitchell214846d2018-09-19 16:57:01 -0700560 printer->Print(StringPrintf("application: label='%s' ",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700561 android::ResTable::normalizeForOutput(label.data()).c_str()));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700562 printer->Print(StringPrintf("icon='%s'", icon.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700563 if (!banner.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700564 printer->Print(StringPrintf(" banner='%s'", banner.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700565 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700566 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700567
568 if (test_only != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700569 printer->Print(StringPrintf("testOnly='%d'\n", test_only));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700570 }
571 if (is_game != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700572 printer->Print("application-isGame\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700573 }
574 if (debuggable != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700575 printer->Print("application-debuggable\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700576 }
577 }
578};
579
580/** Represents <uses-sdk> elements. **/
581class UsesSdkBadging : public ManifestExtractor::Element {
582 public:
583 UsesSdkBadging() = default;
584 const int32_t* min_sdk = nullptr;
585 const std::string* min_sdk_name = nullptr;
586 const int32_t* max_sdk = nullptr;
587 const int32_t* target_sdk = nullptr;
588 const std::string* target_sdk_name = nullptr;
589
590 void Extract(xml::Element* element) override {
591 min_sdk = GetAttributeInteger(FindAttribute(element, MIN_SDK_VERSION_ATTR));
592 min_sdk_name = GetAttributeString(FindAttribute(element, MIN_SDK_VERSION_ATTR));
593 max_sdk = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
594 target_sdk = GetAttributeInteger(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
595 target_sdk_name = GetAttributeString(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
596
597 // Detect the target sdk of the element
598 if ((min_sdk_name && *min_sdk_name == "Donut")
599 || (target_sdk_name && *target_sdk_name == "Donut")) {
600 extractor()->RaiseTargetSdk(4);
601 }
602 if (min_sdk) {
603 extractor()->RaiseTargetSdk(*min_sdk);
604 }
605 if (target_sdk) {
606 extractor()->RaiseTargetSdk(*target_sdk);
607 }
608 }
609
Ryan Mitchell214846d2018-09-19 16:57:01 -0700610 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700611 if (min_sdk) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700612 printer->Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700613 } else if (min_sdk_name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700614 printer->Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700615 }
616 if (max_sdk) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700617 printer->Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700618 }
619 if (target_sdk) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700620 printer->Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700621 } else if (target_sdk_name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700622 printer->Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700623 }
624 }
625};
626
627/** Represents <uses-configuration> elements. **/
628class UsesConfiguarion : public ManifestExtractor::Element {
629 public:
630 UsesConfiguarion() = default;
631 int32_t req_touch_screen = 0;
632 int32_t req_keyboard_type = 0;
633 int32_t req_hard_keyboard = 0;
634 int32_t req_navigation = 0;
635 int32_t req_five_way_nav = 0;
636
637 void Extract(xml::Element* element) override {
638 req_touch_screen = GetAttributeIntegerDefault(
639 FindAttribute(element, REQ_TOUCH_SCREEN_ATTR), 0);
640 req_keyboard_type = GetAttributeIntegerDefault(
641 FindAttribute(element, REQ_KEYBOARD_TYPE_ATTR), 0);
642 req_hard_keyboard = GetAttributeIntegerDefault(
643 FindAttribute(element, REQ_HARD_KEYBOARD_ATTR), 0);
644 req_navigation = GetAttributeIntegerDefault(
645 FindAttribute(element, REQ_NAVIGATION_ATTR), 0);
646 req_five_way_nav = GetAttributeIntegerDefault(
647 FindAttribute(element, REQ_FIVE_WAY_NAV_ATTR), 0);
648 }
649
Ryan Mitchell214846d2018-09-19 16:57:01 -0700650 void Print(text::Printer* printer) override {
651 printer->Print("uses-configuration:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700652 if (req_touch_screen != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700653 printer->Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700654 }
655 if (req_keyboard_type != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700656 printer->Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700657 }
658 if (req_hard_keyboard != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700659 printer->Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700660 }
661 if (req_navigation != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700662 printer->Print(StringPrintf(" reqNavigation='%d'", req_navigation));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700663 }
664 if (req_five_way_nav != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700665 printer->Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700666 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700667 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700668 }
669};
670
671/** Represents <supports-screen> elements. **/
672class SupportsScreen : public ManifestExtractor::Element {
673 public:
674 SupportsScreen() = default;
675 int32_t small_screen = 1;
676 int32_t normal_screen = 1;
677 int32_t large_screen = 1;
678 int32_t xlarge_screen = 1;
679 int32_t any_density = 1;
680 int32_t requires_smallest_width_dp = 0;
681 int32_t compatible_width_limit_dp = 0;
682 int32_t largest_width_limit_dp = 0;
683
684 void Extract(xml::Element* element) override {
685 small_screen = GetAttributeIntegerDefault(FindAttribute(element, SMALL_SCREEN_ATTR), 1);
686 normal_screen = GetAttributeIntegerDefault(FindAttribute(element, NORMAL_SCREEN_ATTR), 1);
687 large_screen = GetAttributeIntegerDefault(FindAttribute(element, LARGE_SCREEN_ATTR), 1);
688 xlarge_screen = GetAttributeIntegerDefault(FindAttribute(element, XLARGE_SCREEN_ATTR), 1);
689 any_density = GetAttributeIntegerDefault(FindAttribute(element, ANY_DENSITY_ATTR), 1);
690
691 requires_smallest_width_dp = GetAttributeIntegerDefault(
692 FindAttribute(element, REQUIRES_SMALLEST_WIDTH_DP_ATTR), 0);
693 compatible_width_limit_dp = GetAttributeIntegerDefault(
694 FindAttribute(element, COMPATIBLE_WIDTH_LIMIT_DP_ATTR), 0);
695 largest_width_limit_dp = GetAttributeIntegerDefault(
696 FindAttribute(element, LARGEST_WIDTH_LIMIT_DP_ATTR), 0);
697
698 // For modern apps, if screen size buckets haven't been specified
699 // but the new width ranges have, then infer the buckets from them.
700 if (small_screen > 0 && normal_screen > 0 && large_screen > 0 && xlarge_screen > 0
701 && requires_smallest_width_dp > 0) {
702 int32_t compat_width = (compatible_width_limit_dp > 0) ? compatible_width_limit_dp
703 : requires_smallest_width_dp;
704 small_screen = (requires_smallest_width_dp <= 240 && compat_width >= 240) ? -1 : 0;
705 normal_screen = (requires_smallest_width_dp <= 320 && compat_width >= 320) ? -1 : 0;
706 large_screen = (requires_smallest_width_dp <= 480 && compat_width >= 480) ? -1 : 0;
707 xlarge_screen = (requires_smallest_width_dp <= 720 && compat_width >= 720) ? -1 : 0;
708 }
709 }
710
Ryan Mitchell214846d2018-09-19 16:57:01 -0700711 void PrintScreens(text::Printer* printer, int32_t target_sdk) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700712 int32_t small_screen_temp = small_screen;
713 int32_t normal_screen_temp = normal_screen;
714 int32_t large_screen_temp = large_screen;
715 int32_t xlarge_screen_temp = xlarge_screen;
716 int32_t any_density_temp = any_density;
717
718 // Determine default values for any unspecified screen sizes,
719 // based on the target SDK of the package. As of 4 (donut)
720 // the screen size support was introduced, so all default to
721 // enabled.
722 if (small_screen_temp > 0) {
723 small_screen_temp = target_sdk >= 4 ? -1 : 0;
724 }
725 if (normal_screen_temp > 0) {
726 normal_screen_temp = -1;
727 }
728 if (large_screen_temp > 0) {
729 large_screen_temp = target_sdk >= 4 ? -1 : 0;
730 }
731 if (xlarge_screen_temp > 0) {
732 // Introduced in Gingerbread.
733 xlarge_screen_temp = target_sdk >= 9 ? -1 : 0;
734 }
735 if (any_density_temp > 0) {
736 any_density_temp = (target_sdk >= 4 || requires_smallest_width_dp > 0
737 || compatible_width_limit_dp > 0) ? -1 : 0;
738 }
739
740 // Print the formatted screen info
Ryan Mitchell214846d2018-09-19 16:57:01 -0700741 printer->Print("supports-screens:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700742 if (small_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700743 printer->Print(" 'small'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700744 }
745 if (normal_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700746 printer->Print(" 'normal'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700747 }
748 if (large_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700749 printer->Print(" 'large'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700750 }
751 if (xlarge_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700752 printer->Print(" 'xlarge'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700753 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700754 printer->Print("\n");
755 printer->Print(StringPrintf("supports-any-density: '%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700756 (any_density_temp ) ? "true" : "false"));
757 if (requires_smallest_width_dp > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700758 printer->Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700759 }
760 if (compatible_width_limit_dp > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700761 printer->Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700762 }
763 if (largest_width_limit_dp > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700764 printer->Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700765 }
766 }
767};
768
769/** Represents <feature-group> elements. **/
770class FeatureGroup : public ManifestExtractor::Element {
771 public:
772 FeatureGroup() = default;
773 std::string label;
774 int32_t open_gles_version = 0;
775
776 void Extract(xml::Element* element) override {
777 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
778 }
779
Ryan Mitchell214846d2018-09-19 16:57:01 -0700780 virtual void PrintGroup(text::Printer* printer) {
781 printer->Print(StringPrintf("feature-group: label='%s'\n", label.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700782 if (open_gles_version > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700783 printer->Print(StringPrintf(" uses-gl-es: '0x%x'\n", open_gles_version));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700784 }
785
786 for (auto feature : features_) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700787 printer->Print(StringPrintf(" uses-feature%s: name='%s'",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700788 (feature.second.required ? "" : "-not-required"),
789 feature.first.data()));
790 if (feature.second.version > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700791 printer->Print(StringPrintf(" version='%d'", feature.second.version));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700792 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700793 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700794 }
795 }
796
797 /** Adds a feature to the feature group. */
798 void AddFeature(const std::string& name, bool required = true, int32_t version = -1) {
799 features_.insert(std::make_pair(name, Feature{ required, version }));
800 if (required) {
801 if (name == "android.hardware.camera.autofocus" ||
802 name == "android.hardware.camera.flash") {
803 AddFeature("android.hardware.camera", true);
804 } else if (name == "android.hardware.location.gps" ||
805 name == "android.hardware.location.network") {
806 AddFeature("android.hardware.location", true);
807 } else if (name == "android.hardware.faketouch.multitouch") {
808 AddFeature("android.hardware.faketouch", true);
809 } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
810 name == "android.hardware.faketouch.multitouch.jazzhands") {
811 AddFeature("android.hardware.faketouch.multitouch", true);
812 AddFeature("android.hardware.faketouch", true);
813 } else if (name == "android.hardware.touchscreen.multitouch") {
814 AddFeature("android.hardware.touchscreen", true);
815 } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
816 name == "android.hardware.touchscreen.multitouch.jazzhands") {
817 AddFeature("android.hardware.touchscreen.multitouch", true);
818 AddFeature("android.hardware.touchscreen", true);
819 } else if (name == "android.hardware.opengles.aep") {
820 const int kOpenGLESVersion31 = 0x00030001;
821 if (kOpenGLESVersion31 > open_gles_version) {
822 open_gles_version = kOpenGLESVersion31;
823 }
824 }
825 }
826 }
827
828 /** Returns true if the feature group has the given feature. */
829 virtual bool HasFeature(const std::string& name) {
830 return features_.find(name) != features_.end();
831 }
832
833 /** Merges the features of another feature group into this group. */
834 void Merge(FeatureGroup* group) {
835 open_gles_version = std::max(open_gles_version, group->open_gles_version);
836 for (auto& feature : group->features_) {
837 features_.insert(feature);
838 }
839 }
840
841 protected:
842 struct Feature {
843 public:
844 bool required = false;
845 int32_t version = -1;
846 };
847
848 /* Mapping of feature names to their properties. */
849 std::map<std::string, Feature> features_;
850};
851
852/**
853 * Represents the default feature group for the application if no <feature-group> elements are
854 * present in the manifest.
855 **/
856class CommonFeatureGroup : public FeatureGroup {
857 public:
858 CommonFeatureGroup() = default;
Ryan Mitchell214846d2018-09-19 16:57:01 -0700859 void PrintGroup(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700860 FeatureGroup::PrintGroup(printer);
861
862 // Also print the implied features
863 for (auto feature : implied_features_) {
864 if (features_.find(feature.first) == features_.end()) {
865 const char* sdk23 = feature.second.implied_from_sdk_k23 ? "-sdk-23" : "";
Ryan Mitchell214846d2018-09-19 16:57:01 -0700866 printer->Print(StringPrintf(" uses-feature%s: name='%s'\n", sdk23, feature.first.data()));
867 printer->Print(StringPrintf(" uses-implied-feature%s: name='%s' reason='", sdk23,
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700868 feature.first.data()));
869
870 // Print the reasons as a sentence
871 size_t count = 0;
872 for (auto reason : feature.second.reasons) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700873 printer->Print(reason);
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700874 if (count + 2 < feature.second.reasons.size()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700875 printer->Print(", ");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700876 } else if (count + 1 < feature.second.reasons.size()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700877 printer->Print(", and ");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700878 }
879 count++;
880 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700881 printer->Print("'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700882 }
883 }
884 }
885
886 /** Returns true if the feature group has the given feature. */
887 bool HasFeature(const std::string& name) override {
888 return FeatureGroup::HasFeature(name)
889 || implied_features_.find(name) != implied_features_.end();
890 }
891
892 /** Adds a feature to a set of implied features not explicitly requested in the manifest. */
893 void addImpliedFeature(const std::string& name, const std::string& reason, bool sdk23 = false) {
894 auto entry = implied_features_.find(name);
895 if (entry == implied_features_.end()) {
896 implied_features_.insert(std::make_pair(name, ImpliedFeature(sdk23)));
897 entry = implied_features_.find(name);
898 }
899
900 // A non-sdk 23 implied feature takes precedence.
901 if (entry->second.implied_from_sdk_k23 && !sdk23) {
902 entry->second.implied_from_sdk_k23 = false;
903 }
904
905 entry->second.reasons.insert(reason);
906 }
907
908 /**
909 * Adds a feature to a set of implied features for all features that are implied by the presence
910 * of the permission.
911 **/
912 void addImpliedFeaturesForPermission(int32_t targetSdk, const std::string& name, bool sdk23) {
913 if (name == "android.permission.CAMERA") {
914 addImpliedFeature("android.hardware.camera",
915 StringPrintf("requested %s permission", name.data()),
916 sdk23);
917
918 } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
919 if (targetSdk < SDK_LOLLIPOP) {
920 addImpliedFeature("android.hardware.location.gps",
921 StringPrintf("requested %s permission", name.data()),
922 sdk23);
923 addImpliedFeature("android.hardware.location.gps",
924 StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
925 sdk23);
926 }
927 addImpliedFeature("android.hardware.location",
928 StringPrintf("requested %s permission", name.data()),
929 sdk23);
930
931 } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
932 if (targetSdk < SDK_LOLLIPOP) {
933 addImpliedFeature("android.hardware.location.network",
934 StringPrintf("requested %s permission", name.data()),
935 sdk23);
936 addImpliedFeature("android.hardware.location.network",
937 StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
938 sdk23);
939 }
940 addImpliedFeature("android.hardware.location",
941 StringPrintf("requested %s permission", name.data()),
942 sdk23);
943
944 } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
945 name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
946 name == "android.permission.INSTALL_LOCATION_PROVIDER") {
947 addImpliedFeature("android.hardware.location",
948 StringPrintf("requested %s permission", name.data()),
949 sdk23);
950
951 } else if (name == "android.permission.BLUETOOTH" ||
952 name == "android.permission.BLUETOOTH_ADMIN") {
953 if (targetSdk > SDK_DONUT) {
954 addImpliedFeature("android.hardware.bluetooth",
955 StringPrintf("requested %s permission", name.data()),
956 sdk23);
957 addImpliedFeature("android.hardware.bluetooth",
958 StringPrintf("targetSdkVersion > %d", SDK_DONUT),
959 sdk23);
960 }
961
962 } else if (name == "android.permission.RECORD_AUDIO") {
963 addImpliedFeature("android.hardware.microphone",
964 StringPrintf("requested %s permission", name.data()),
965 sdk23);
966
967 } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
968 name == "android.permission.CHANGE_WIFI_STATE" ||
969 name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
970 addImpliedFeature("android.hardware.wifi",
971 StringPrintf("requested %s permission", name.data()),
972 sdk23);
973
974 } else if (name == "android.permission.CALL_PHONE" ||
975 name == "android.permission.CALL_PRIVILEGED" ||
976 name == "android.permission.MODIFY_PHONE_STATE" ||
977 name == "android.permission.PROCESS_OUTGOING_CALLS" ||
978 name == "android.permission.READ_SMS" ||
979 name == "android.permission.RECEIVE_SMS" ||
980 name == "android.permission.RECEIVE_MMS" ||
981 name == "android.permission.RECEIVE_WAP_PUSH" ||
982 name == "android.permission.SEND_SMS" ||
983 name == "android.permission.WRITE_APN_SETTINGS" ||
984 name == "android.permission.WRITE_SMS") {
985 addImpliedFeature("android.hardware.telephony",
986 "requested a telephony permission",
987 sdk23);
988 }
989 }
990
991 private:
992 /**
993 * Represents a feature that has been automatically added due to a pre-requisite or for some
994 * other reason.
995 */
996 struct ImpliedFeature {
997 explicit ImpliedFeature(bool sdk23 = false) : implied_from_sdk_k23(sdk23) {}
998
999 /** List of human-readable reasons for why this feature was implied. */
1000 std::set<std::string> reasons;
1001
1002 // Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)
1003 bool implied_from_sdk_k23;
1004 };
1005
1006 /* Mapping of implied feature names to their properties. */
1007 std::map<std::string, ImpliedFeature> implied_features_;
1008};
1009
1010/** Represents <uses-feature> elements. **/
1011class UsesFeature : public ManifestExtractor::Element {
1012 public:
1013 UsesFeature() = default;
1014 void Extract(xml::Element* element) override {
1015 const std::string* name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1016 int32_t* gl = GetAttributeInteger(FindAttribute(element, GL_ES_VERSION_ATTR));
1017 bool required = GetAttributeIntegerDefault(
1018 FindAttribute(element, REQUIRED_ATTR), true) != 0;
1019 int32_t version = GetAttributeIntegerDefault(
1020 FindAttribute(element, kAndroidNamespace, "version"), 0);
1021
1022 // Add the feature to the parent feature group element if one exists; otherwise, add it to the
1023 // common feature group
1024 FeatureGroup* feature_group = ElementCast<FeatureGroup>(extractor()->parent_stack()[0]);
1025 if (!feature_group) {
1026 feature_group = extractor()->GetCommonFeatureGroup();
1027 } else {
1028 // All features in side of <feature-group> elements are required.
1029 required = true;
1030 }
1031
1032 if (name) {
1033 feature_group->AddFeature(*name, required, version);
1034 } else if (gl) {
1035 feature_group->open_gles_version = std::max(feature_group->open_gles_version, *gl);
1036 }
1037 }
1038};
1039
1040/** Represents <uses-permission> elements. **/
1041class UsesPermission : public ManifestExtractor::Element {
1042 public:
1043 UsesPermission() = default;
1044 std::string name;
1045 std::string requiredFeature;
1046 std::string requiredNotFeature;
1047 int32_t required = true;
1048 int32_t maxSdkVersion = -1;
1049
1050 void Extract(xml::Element* element) override {
1051 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1052 requiredFeature = GetAttributeStringDefault(
1053 FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
1054 requiredNotFeature = GetAttributeStringDefault(
1055 FindAttribute(element, REQUIRED_NOT_FEATURE_ATTR), "");
1056 required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
1057 maxSdkVersion = GetAttributeIntegerDefault(
1058 FindAttribute(element, MAX_SDK_VERSION_ATTR), -1);
1059
1060 if (!name.empty()) {
1061 CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
1062 common->addImpliedFeaturesForPermission(extractor()->target_sdk(), name, false);
1063 }
1064 }
1065
Ryan Mitchell214846d2018-09-19 16:57:01 -07001066 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001067 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001068 printer->Print(StringPrintf("uses-permission: name='%s'", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001069 if (maxSdkVersion >= 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001070 printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001071 }
1072 if (!requiredFeature.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001073 printer->Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001074 }
1075 if (!requiredNotFeature.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001076 printer->Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001077 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001078 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001079 if (required == 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001080 printer->Print(StringPrintf("optional-permission: name='%s'", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001081 if (maxSdkVersion >= 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001082 printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001083 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001084 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001085 }
1086 }
1087 }
1088
Ryan Mitchell214846d2018-09-19 16:57:01 -07001089 void PrintImplied(text::Printer* printer, const std::string& reason) {
1090 printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001091 if (maxSdkVersion >= 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001092 printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001093 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001094 printer->Print(StringPrintf(" reason='%s'\n", reason.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001095 }
1096};
1097
1098/** Represents <uses-permission-sdk-23> elements. **/
1099class UsesPermissionSdk23 : public ManifestExtractor::Element {
1100 public:
1101 UsesPermissionSdk23() = default;
1102 const std::string* name = nullptr;
1103 const int32_t* maxSdkVersion = nullptr;
1104
1105 void Extract(xml::Element* element) override {
1106 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1107 maxSdkVersion = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
1108
1109 if (name) {
1110 CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
1111 common->addImpliedFeaturesForPermission(extractor()->target_sdk(), *name, true);
1112 }
1113 }
1114
Ryan Mitchell214846d2018-09-19 16:57:01 -07001115 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001116 if (name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001117 printer->Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001118 if (maxSdkVersion) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001119 printer->Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001120 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001121 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001122 }
1123 }
1124};
1125
1126/** Represents <permission> elements. These elements are only printing when dumping permissions. **/
1127class Permission : public ManifestExtractor::Element {
1128 public:
1129 Permission() = default;
1130 std::string name;
1131
1132 void Extract(xml::Element* element) override {
1133 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1134 }
1135
Ryan Mitchell214846d2018-09-19 16:57:01 -07001136 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001137 if (extractor()->options_.only_permissions && !name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001138 printer->Print(StringPrintf("permission: %s\n", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001139 }
1140 }
1141};
1142
1143/** Represents <activity> elements. **/
1144class Activity : public ManifestExtractor::Element {
1145 public:
1146 Activity() = default;
1147 std::string name;
1148 std::string icon;
1149 std::string label;
1150 std::string banner;
1151
1152 bool has_component_ = false;
1153 bool has_launcher_category = false;
1154 bool has_leanback_launcher_category = false;
1155 bool has_main_action = false;
1156
1157 void Extract(xml::Element* element) override {
1158 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1159 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
1160 icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
1161 banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
1162
1163 // Retrieve the package name from the manifest
1164 std::string package;
1165 for (auto& parent : extractor()->parent_stack()) {
1166 if (auto manifest = ElementCast<Manifest>(parent)) {
1167 package = manifest->package;
1168 break;
1169 }
1170 }
1171
1172 // Fully qualify the activity name
1173 ssize_t idx = name.find(".");
1174 if (idx == 0) {
1175 name = package + name;
1176 } else if (idx < 0) {
1177 name = package + "." + name;
1178 }
1179
1180 auto orientation = GetAttributeInteger(FindAttribute(element, SCREEN_ORIENTATION_ATTR));
1181 if (orientation) {
1182 CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
1183 int orien = *orientation;
1184 if (orien == 0 || orien == 6 || orien == 8) {
1185 // Requests landscape, sensorLandscape, or reverseLandscape.
1186 common->addImpliedFeature("android.hardware.screen.landscape",
1187 "one or more activities have specified a landscape orientation",
1188 false);
1189 } else if (orien == 1 || orien == 7 || orien == 9) {
1190 // Requests portrait, sensorPortrait, or reversePortrait.
1191 common->addImpliedFeature("android.hardware.screen.portrait",
1192 "one or more activities have specified a portrait orientation",
1193 false);
1194 }
1195 }
1196 }
1197
Ryan Mitchell214846d2018-09-19 16:57:01 -07001198 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001199 // Print whether the activity has the HOME category and a the MAIN action
1200 if (has_main_action && has_launcher_category) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001201 printer->Print("launchable-activity:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001202 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001203 printer->Print(StringPrintf(" name='%s' ", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001204 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001205 printer->Print(StringPrintf(" label='%s' icon='%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001206 android::ResTable::normalizeForOutput(label.data()).c_str(),
1207 icon.data()));
1208 }
1209
1210 // Print wether the activity has the HOME category and a the MAIN action
1211 if (has_leanback_launcher_category) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001212 printer->Print("leanback-launchable-activity:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001213 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001214 printer->Print(StringPrintf(" name='%s' ", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001215 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001216 printer->Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001217 android::ResTable::normalizeForOutput(label.data()).c_str(),
1218 icon.data(), banner.data()));
1219 }
1220 }
1221};
1222
1223/** Represents <intent-filter> elements. */
1224class IntentFilter : public ManifestExtractor::Element {
1225 public:
1226 IntentFilter() = default;
1227};
1228
1229/** Represents <category> elements. */
1230class Category : public ManifestExtractor::Element {
1231 public:
1232 Category() = default;
1233 std::string component = "";
1234
1235 void Extract(xml::Element* element) override {
1236 const std::string* category = GetAttributeString(FindAttribute(element, NAME_ATTR));
1237
1238 auto parent_stack = extractor()->parent_stack();
1239 if (category && ElementCast<IntentFilter>(parent_stack[0])
1240 && ElementCast<Activity>(parent_stack[1])) {
1241 Activity* activity = ElementCast<Activity>(parent_stack[1]);
1242
1243 if (*category == "android.intent.category.LAUNCHER") {
1244 activity->has_launcher_category = true;
1245 } else if (*category == "android.intent.category.LEANBACK_LAUNCHER") {
1246 activity->has_leanback_launcher_category = true;
1247 } else if (*category == "android.intent.category.HOME") {
1248 component = "launcher";
1249 }
1250 }
1251 }
1252};
1253
1254/**
1255 * Represents <provider> elements. The elements may have an <intent-filter> which may have <action>
1256 * elements nested within.
1257 **/
1258class Provider : public ManifestExtractor::Element {
1259 public:
1260 Provider() = default;
1261 bool has_required_saf_attributes = false;
1262
1263 void Extract(xml::Element* element) override {
1264 const int32_t* exported = GetAttributeInteger(FindAttribute(element, EXPORTED_ATTR));
1265 const int32_t* grant_uri_permissions = GetAttributeInteger(
1266 FindAttribute(element, GRANT_URI_PERMISSIONS_ATTR));
1267 const std::string* permission = GetAttributeString(
1268 FindAttribute(element, PERMISSION_ATTR));
1269
1270 has_required_saf_attributes = ((exported && *exported != 0)
1271 && (grant_uri_permissions && *grant_uri_permissions != 0)
1272 && (permission && *permission == "android.permission.MANAGE_DOCUMENTS"));
1273 }
1274};
1275
1276/** Represents <receiver> elements. **/
1277class Receiver : public ManifestExtractor::Element {
1278 public:
1279 Receiver() = default;
1280 const std::string* permission = nullptr;
1281 bool has_component = false;
1282
1283 void Extract(xml::Element* element) override {
1284 permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
1285 }
1286};
1287
1288/**Represents <service> elements. **/
1289class Service : public ManifestExtractor::Element {
1290 public:
1291 Service() = default;
1292 const std::string* permission = nullptr;
1293 bool has_component = false;
1294
1295 void Extract(xml::Element* element) override {
1296 permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
1297 }
1298};
1299
1300/** Represents <uses-library> elements. **/
1301class UsesLibrary : public ManifestExtractor::Element {
1302 public:
1303 UsesLibrary() = default;
1304 std::string name;
1305 int required;
1306
1307 void Extract(xml::Element* element) override {
1308 auto parent_stack = extractor()->parent_stack();
1309 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1310 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1311 required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
1312 }
1313 }
1314
Ryan Mitchell214846d2018-09-19 16:57:01 -07001315 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001316 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001317 printer->Print(StringPrintf("uses-library%s:'%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001318 (required == 0) ? "-not-required" : "", name.data()));
1319 }
1320 }
1321};
1322
Dianne Hackborn813d7502018-10-02 16:59:46 -07001323/** Represents <static-library> elements. **/
1324class StaticLibrary : public ManifestExtractor::Element {
1325 public:
1326 StaticLibrary() = default;
1327 std::string name;
1328 int version;
1329 int versionMajor;
1330
1331 void Extract(xml::Element* element) override {
1332 auto parent_stack = extractor()->parent_stack();
1333 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1334 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1335 version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
1336 versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
1337 }
1338 }
1339
Ryan Mitchell214846d2018-09-19 16:57:01 -07001340 void Print(text::Printer* printer) override {
1341 printer->Print(StringPrintf(
Dianne Hackborn813d7502018-10-02 16:59:46 -07001342 "static-library: name='%s' version='%d' versionMajor='%d'\n",
1343 name.data(), version, versionMajor));
1344 }
1345};
1346
1347/** Represents <uses-static-library> elements. **/
1348class UsesStaticLibrary : public ManifestExtractor::Element {
1349 public:
1350 UsesStaticLibrary() = default;
1351 std::string name;
1352 int version;
1353 int versionMajor;
1354 std::vector<std::string> certDigests;
1355
1356 void Extract(xml::Element* element) override {
1357 auto parent_stack = extractor()->parent_stack();
1358 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1359 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1360 version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
1361 versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
1362 AddCertDigest(element);
1363 }
1364 }
1365
1366 void AddCertDigest(xml::Element* element) {
1367 std::string digest = GetAttributeStringDefault(FindAttribute(element, CERT_DIGEST_ATTR), "");
1368 // We allow ":" delimiters in the SHA declaration as this is the format
1369 // emitted by the certtool making it easy for developers to copy/paste.
1370 digest.erase(std::remove(digest.begin(), digest.end(), ':'), digest.end());
1371 if (!digest.empty()) {
1372 certDigests.push_back(digest);
1373 }
1374 }
1375
Ryan Mitchell214846d2018-09-19 16:57:01 -07001376 void Print(text::Printer* printer) override {
1377 printer->Print(StringPrintf(
Dianne Hackborn813d7502018-10-02 16:59:46 -07001378 "uses-static-library: name='%s' version='%d' versionMajor='%d'",
1379 name.data(), version, versionMajor));
1380 for (size_t i = 0; i < certDigests.size(); i++) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001381 printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
Dianne Hackborn813d7502018-10-02 16:59:46 -07001382 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001383 printer->Print("\n");
Dianne Hackborn813d7502018-10-02 16:59:46 -07001384 }
1385};
1386
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001387/**
1388 * Represents <meta-data> elements. These tags are only printed when a flag is passed in to
1389 * explicitly enable meta data printing.
1390 **/
1391class MetaData : public ManifestExtractor::Element {
1392 public:
1393 MetaData() = default;
1394 std::string name;
Ryan Mitchell2250c932018-10-04 11:07:40 -07001395 std::string value;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001396 const int* value_int;
Ryan Mitchell2250c932018-10-04 11:07:40 -07001397 std::string resource;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001398 const int* resource_int;
1399
1400 void Extract(xml::Element* element) override {
1401 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
Ryan Mitchell2250c932018-10-04 11:07:40 -07001402 value = GetAttributeStringDefault(FindAttribute(element, VALUE_ATTR), "");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001403 value_int = GetAttributeInteger(FindAttribute(element, VALUE_ATTR));
Ryan Mitchell2250c932018-10-04 11:07:40 -07001404 resource = GetAttributeStringDefault(FindAttribute(element, RESOURCE_ATTR), "");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001405 resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR));
1406 }
1407
Ryan Mitchell214846d2018-09-19 16:57:01 -07001408 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001409 if (extractor()->options_.include_meta_data && !name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001410 printer->Print(StringPrintf("meta-data: name='%s' ", name.data()));
Ryan Mitchell2250c932018-10-04 11:07:40 -07001411 if (!value.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001412 printer->Print(StringPrintf("value='%s' ", value.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001413 } else if (value_int) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001414 printer->Print(StringPrintf("value='%d' ", *value_int));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001415 } else {
Ryan Mitchell2250c932018-10-04 11:07:40 -07001416 if (!resource.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001417 printer->Print(StringPrintf("resource='%s' ", resource.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001418 } else if (resource_int) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001419 printer->Print(StringPrintf("resource='%d' ", *resource_int));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001420 }
1421 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001422 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001423 }
1424 }
1425};
1426
1427/**
1428 * Represents <action> elements. Detects the presence of certain activity, provider, receiver, and
1429 * service components.
1430 **/
1431class Action : public ManifestExtractor::Element {
1432 public:
1433 Action() = default;
1434 std::string component = "";
1435
1436 void Extract(xml::Element* element) override {
1437 auto parent_stack = extractor()->parent_stack();
1438 std::string action = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1439
1440 if (ElementCast<IntentFilter>(parent_stack[0])) {
1441 if (ElementCast<Activity>(parent_stack[1])) {
1442 // Detects the presence of a particular type of activity.
1443 Activity* activity = ElementCast<Activity>(parent_stack[1]);
1444 auto map = std::map<std::string, std::string>({
1445 { "android.intent.action.MAIN" , "main" },
1446 { "android.intent.action.VIDEO_CAMERA" , "camera" },
1447 { "android.intent.action.STILL_IMAGE_CAMERA_SECURE" , "camera-secure" },
1448 });
1449
1450 auto entry = map.find(action);
1451 if (entry != map.end()) {
1452 component = entry->second;
1453 activity->has_component_ = true;
1454 }
1455
1456 if (action == "android.intent.action.MAIN") {
1457 activity->has_main_action = true;
1458 }
1459
1460 } else if (ElementCast<Receiver>(parent_stack[1])) {
1461 // Detects the presence of a particular type of receiver. If the action requires a
1462 // permission, then the receiver element is checked for the permission.
1463 Receiver* receiver = ElementCast<Receiver>(parent_stack[1]);
1464 auto map = std::map<std::string, std::string>({
1465 { "android.appwidget.action.APPWIDGET_UPDATE" , "app-widget" },
1466 { "android.app.action.DEVICE_ADMIN_ENABLED" , "device-admin" },
1467 });
1468
1469 auto permissions = std::map<std::string, std::string>({
1470 { "android.app.action.DEVICE_ADMIN_ENABLED" , "android.permission.BIND_DEVICE_ADMIN" },
1471 });
1472
1473 auto entry = map.find(action);
1474 auto permission = permissions.find(action);
1475 if (entry != map.end() && (permission == permissions.end()
1476 || (receiver->permission && permission->second == *receiver->permission))) {
1477 receiver->has_component = true;
1478 component = entry->second;
1479 }
1480
1481 } else if (ElementCast<Service>(parent_stack[1])) {
1482 // Detects the presence of a particular type of service. If the action requires a
1483 // permission, then the service element is checked for the permission.
1484 Service* service = ElementCast<Service>(parent_stack[1]);
1485 auto map = std::map<std::string, std::string>({
1486 { "android.view.InputMethod" , "ime" },
1487 { "android.service.wallpaper.WallpaperService" , "wallpaper" },
1488 { "android.accessibilityservice.AccessibilityService" , "accessibility" },
1489 { "android.printservice.PrintService" , "print-service" },
1490 { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" , "host-apdu" },
1491 { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" , "offhost-apdu" },
1492 { "android.service.notification.NotificationListenerService" ,"notification-listener" },
1493 { "android.service.dreams.DreamService" , "dream" },
1494 });
1495
1496 auto permissions = std::map<std::string, std::string>({
1497 { "android.accessibilityservice.AccessibilityService" ,
1498 "android.permission.BIND_ACCESSIBILITY_SERVICE" },
1499 { "android.printservice.PrintService" , "android.permission.BIND_PRINT_SERVICE" },
1500 { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" ,
1501 "android.permission.BIND_NFC_SERVICE" },
1502 { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" ,
1503 "android.permission.BIND_NFC_SERVICE" },
1504 { "android.service.notification.NotificationListenerService" ,
1505 "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" },
1506 { "android.service.dreams.DreamService" , "android.permission.BIND_DREAM_SERVICE" },
1507 });
1508
1509 auto entry = map.find(action);
1510 auto permission = permissions.find(action);
1511 if (entry != map.end() && (permission == permissions.end()
1512 || (service->permission && permission->second == *service->permission))) {
1513 service->has_component= true;
1514 component = entry->second;
1515 }
1516
1517 } else if (ElementCast<Provider>(parent_stack[1])) {
1518 // Detects the presence of a particular type of receiver. If the provider requires a
1519 // permission, then the provider element is checked for the permission.
1520 // Detect whether this action
1521 Provider* provider = ElementCast<Provider>(parent_stack[1]);
1522 if (action == "android.content.action.DOCUMENTS_PROVIDER"
1523 && provider->has_required_saf_attributes) {
1524 component = "document-provider";
1525 }
1526 }
1527 }
1528
1529 // Represents a searchable interface
1530 if (action == "android.intent.action.SEARCH") {
1531 component = "search";
1532 }
1533 }
1534};
1535
1536/**
1537 * Represents <supports-input> elements. The element may have <input-type> elements nested within.
1538 **/
1539class SupportsInput : public ManifestExtractor::Element {
1540 public:
1541 SupportsInput() = default;
1542 std::vector<std::string> inputs;
1543
Ryan Mitchell214846d2018-09-19 16:57:01 -07001544 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001545 const size_t size = inputs.size();
1546 if (size > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001547 printer->Print("supports-input: '");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001548 for (size_t i = 0; i < size; i++) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001549 printer->Print(StringPrintf("value='%s' ", inputs[i].data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001550 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001551 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001552 }
1553 }
1554};
1555
1556/** Represents <input-type> elements. **/
1557class InputType : public ManifestExtractor::Element {
1558 public:
1559 InputType() = default;
1560 void Extract(xml::Element* element) override {
1561 auto name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1562 auto parent_stack = extractor()->parent_stack();
1563
1564 // Add the input to the set of supported inputs
1565 if (name && ElementCast<SupportsInput>(parent_stack[0])) {
1566 SupportsInput* supports = ElementCast<SupportsInput>(parent_stack[0]);
1567 supports->inputs.push_back(*name);
1568 }
1569 }
1570};
1571
1572/** Represents <original-package> elements. **/
1573class OriginalPackage : public ManifestExtractor::Element {
1574 public:
1575 OriginalPackage() = default;
1576 const std::string* name = nullptr;
1577
1578 void Extract(xml::Element* element) override {
1579 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1580 }
1581
Ryan Mitchell214846d2018-09-19 16:57:01 -07001582 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001583 if (name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001584 printer->Print(StringPrintf("original-package:'%s'\n", name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001585 }
1586 }
1587};
1588
1589/** * Represents <package-verifier> elements. **/
1590class PackageVerifier : public ManifestExtractor::Element {
1591 public:
1592 PackageVerifier() = default;
1593 const std::string* name = nullptr;
1594 const std::string* public_key = nullptr;
1595
1596 void Extract(xml::Element* element) override {
1597 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1598 public_key = GetAttributeString(FindAttribute(element, PUBLIC_KEY_ATTR));
1599 }
1600
Ryan Mitchell214846d2018-09-19 16:57:01 -07001601 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001602 if (name && public_key) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001603 printer->Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001604 name->data(), public_key->data()));
1605 }
1606 }
1607};
1608
1609/** Represents <uses-package> elements. **/
1610class UsesPackage : public ManifestExtractor::Element {
1611 public:
1612 UsesPackage() = default;
Dianne Hackborn813d7502018-10-02 16:59:46 -07001613 const std::string* packageType = nullptr;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001614 const std::string* name = nullptr;
Dianne Hackborn813d7502018-10-02 16:59:46 -07001615 int version;
1616 int versionMajor;
1617 std::vector<std::string> certDigests;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001618
1619 void Extract(xml::Element* element) override {
Dianne Hackborn813d7502018-10-02 16:59:46 -07001620 auto parent_stack = extractor()->parent_stack();
1621 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1622 packageType = GetAttributeString(FindAttribute(element, PACKAGE_TYPE_ATTR));
1623 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1624 version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
1625 versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
1626 AddCertDigest(element);
1627 }
1628 }
1629
1630 void AddCertDigest(xml::Element* element) {
1631 std::string digest = GetAttributeStringDefault(FindAttribute(element, CERT_DIGEST_ATTR), "");
1632 // We allow ":" delimiters in the SHA declaration as this is the format
1633 // emitted by the certtool making it easy for developers to copy/paste.
1634 digest.erase(std::remove(digest.begin(), digest.end(), ':'), digest.end());
1635 if (!digest.empty()) {
1636 certDigests.push_back(digest);
1637 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001638 }
1639
Ryan Mitchell214846d2018-09-19 16:57:01 -07001640 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001641 if (name) {
Dianne Hackborn813d7502018-10-02 16:59:46 -07001642 if (packageType) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001643 printer->Print(StringPrintf(
Dianne Hackborn813d7502018-10-02 16:59:46 -07001644 "uses-typed-package: type='%s' name='%s' version='%d' versionMajor='%d'",
1645 packageType->data(), name->data(), version, versionMajor));
1646 for (size_t i = 0; i < certDigests.size(); i++) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001647 printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
Dianne Hackborn813d7502018-10-02 16:59:46 -07001648 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001649 printer->Print("\n");
Dianne Hackborn813d7502018-10-02 16:59:46 -07001650 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001651 printer->Print(StringPrintf("uses-package:'%s'\n", name->data()));
Dianne Hackborn813d7502018-10-02 16:59:46 -07001652 }
1653 }
1654 }
1655};
1656
1657/** Represents <additional-certificate> elements. **/
1658class AdditionalCertificate : public ManifestExtractor::Element {
1659 public:
1660 AdditionalCertificate() = default;
1661
1662 void Extract(xml::Element* element) override {
1663 auto parent_stack = extractor()->parent_stack();
1664 if (parent_stack.size() > 0) {
1665 if (ElementCast<UsesPackage>(parent_stack[0])) {
1666 UsesPackage* uses = ElementCast<UsesPackage>(parent_stack[0]);
1667 uses->AddCertDigest(element);
1668 } else if (ElementCast<UsesStaticLibrary>(parent_stack[0])) {
1669 UsesStaticLibrary* uses = ElementCast<UsesStaticLibrary>(parent_stack[0]);
1670 uses->AddCertDigest(element);
1671 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001672 }
1673 }
1674};
1675
1676/** Represents <screen> elements found in <compatible-screens> elements. */
1677class Screen : public ManifestExtractor::Element {
1678 public:
1679 Screen() = default;
1680 const int32_t* size = nullptr;
1681 const int32_t* density = nullptr;
1682
1683 void Extract(xml::Element* element) override {
1684 size = GetAttributeInteger(FindAttribute(element, SCREEN_SIZE_ATTR));
1685 density = GetAttributeInteger(FindAttribute(element, SCREEN_DENSITY_ATTR));
1686 }
1687};
1688
1689/**
1690 * Represents <compatible-screens> elements. These elements have <screen> elements nested within
1691 * that each denote a supported screen size and screen density.
1692 **/
1693class CompatibleScreens : public ManifestExtractor::Element {
1694 public:
1695 CompatibleScreens() = default;
Ryan Mitchell214846d2018-09-19 16:57:01 -07001696 void Print(text::Printer* printer) override {
1697 printer->Print("compatible-screens:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001698
1699 bool first = true;
1700 ForEachChild(this, [&printer, &first](ManifestExtractor::Element* el){
1701 if (auto screen = ElementCast<Screen>(el)) {
1702 if (first) {
1703 first = false;
1704 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001705 printer->Print(",");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001706 }
1707
1708 if (screen->size && screen->density) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001709 printer->Print(StringPrintf("'%d/%d'", *screen->size, *screen->density));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001710 }
1711 }
1712 });
Ryan Mitchell214846d2018-09-19 16:57:01 -07001713 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001714 }
1715};
1716
1717/** Represents <supports-gl-texture> elements. **/
1718class SupportsGlTexture : public ManifestExtractor::Element {
1719 public:
1720 SupportsGlTexture() = default;
1721 const std::string* name = nullptr;
1722
1723 void Extract(xml::Element* element) override {
1724 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1725 }
1726
Ryan Mitchell214846d2018-09-19 16:57:01 -07001727 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001728 if (name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001729 printer->Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001730 }
1731 }
1732};
1733
1734/** Recursively prints the extracted badging element. */
Ryan Mitchell214846d2018-09-19 16:57:01 -07001735static void Print(ManifestExtractor::Element* el, text::Printer* printer) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001736 el->Print(printer);
1737 for (auto &child : el->children()) {
1738 Print(child.get(), printer);
1739 }
1740}
1741
Ryan Mitchell214846d2018-09-19 16:57:01 -07001742bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001743 // Load the manifest
1744 std::unique_ptr<xml::XmlResource> doc = apk_->LoadXml("AndroidManifest.xml", diag);
1745 if (doc == nullptr) {
1746 diag->Error(DiagMessage() << "failed to find AndroidManifest.xml");
1747 return false;
1748 }
1749
1750 xml::Element* element = doc->root.get();
1751 if (element->name != "manifest") {
1752 diag->Error(DiagMessage() << "manifest does not start with <manifest> tag");
1753 return false;
1754 }
1755
1756 // Print only the <uses-permission>, <uses-permission-sdk23>, and <permission> elements if
1757 // printing only permission elements is requested
1758 if (options_.only_permissions) {
1759 std::unique_ptr<ManifestExtractor::Element> manifest_element =
1760 ManifestExtractor::Element::Inflate(this, element);
1761
1762 if (auto manifest = ElementCast<Manifest>(manifest_element.get())) {
1763 for (xml::Element* child : element->GetChildElements()) {
1764 if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
1765 || child->name == "permission") {
1766 auto permission_element = ManifestExtractor::Element::Inflate(this, child);
1767 manifest->AddChild(permission_element);
1768 }
1769 }
1770
Ryan Mitchell214846d2018-09-19 16:57:01 -07001771 printer->Print(StringPrintf("package: %s\n", manifest->package.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001772 ForEachChild(manifest, [&printer](ManifestExtractor::Element* el) -> void {
1773 el->Print(printer);
1774 });
1775
1776 return true;
1777 }
1778
1779 return false;
1780 }
1781
1782 // Collect information about the resource configurations
1783 if (apk_->GetResourceTable()) {
1784 for (auto &package : apk_->GetResourceTable()->packages) {
1785 for (auto &type : package->types) {
1786 for (auto &entry : type->entries) {
1787 for (auto &value : entry->values) {
1788 std::string locale_str = value->config.GetBcp47LanguageTag();
1789
1790 // Collect all the unique locales of the apk
1791 if (locales_.find(locale_str) == locales_.end()) {
1792 ConfigDescription config = ManifestExtractor::DummyConfig();
1793 config.setBcp47Locale(locale_str.data());
1794 locales_.insert(std::make_pair(locale_str, config));
1795 }
1796
1797 // Collect all the unique density of the apk
1798 uint16_t density = (value->config.density == 0) ? (uint16_t) 160
1799 : value->config.density;
1800 if (densities_.find(density) == densities_.end()) {
1801 ConfigDescription config = ManifestExtractor::DummyConfig();
1802 config.density = density;
1803 densities_.insert(std::make_pair(density, config));
1804 }
1805 }
1806 }
1807 }
1808 }
1809 }
1810
1811 // Extract badging information
1812 auto root = Visit(element);
1813
1814 // Print the elements in order seen
1815 Print(root.get(), printer);
1816
1817 /** Recursively checks the extracted elements for the specified permission. **/
1818 auto FindPermission = [&](ManifestExtractor::Element* root,
1819 const std::string& name) -> ManifestExtractor::Element* {
1820 return FindElement(root, [&](ManifestExtractor::Element* el) -> bool {
1821 if (UsesPermission* permission = ElementCast<UsesPermission>(el)) {
1822 return permission->name == name;
1823 }
1824 return false;
1825 });
1826 };
1827
1828 auto PrintPermission = [&printer](const std::string& name, const std::string& reason,
1829 int32_t max_sdk_version) -> void {
1830 auto permission = util::make_unique<UsesPermission>();
1831 permission->name = name;
1832 permission->maxSdkVersion = max_sdk_version;
1833 permission->Print(printer);
1834 permission->PrintImplied(printer, reason);
1835 };
1836
1837 // Implied permissions
1838 // Pre-1.6 implicitly granted permission compatibility logic
1839 CommonFeatureGroup* common_feature_group = GetCommonFeatureGroup();
1840 bool insert_write_external = false;
1841 auto write_external_permission = ElementCast<UsesPermission>(
1842 FindPermission(root.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
1843
1844 if (target_sdk() < 4) {
1845 if (!write_external_permission) {
1846 PrintPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
1847 insert_write_external = true;
1848 }
1849
1850 if (!FindPermission(root.get(), "android.permission.READ_PHONE_STATE")) {
1851 PrintPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
1852 }
1853 }
1854
1855 // If the application has requested WRITE_EXTERNAL_STORAGE, we will
1856 // force them to always take READ_EXTERNAL_STORAGE as well. We always
1857 // do this (regardless of target API version) because we can't have
1858 // an app with write permission but not read permission.
1859 auto read_external = FindPermission(root.get(), "android.permission.READ_EXTERNAL_STORAGE");
1860 if (!read_external && (insert_write_external || write_external_permission)) {
1861 PrintPermission("android.permission.READ_EXTERNAL_STORAGE",
1862 "requested WRITE_EXTERNAL_STORAGE",
1863 (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
1864 }
1865
1866 // Pre-JellyBean call log permission compatibility.
1867 if (target_sdk() < 16) {
1868 if (!FindPermission(root.get(), "android.permission.READ_CALL_LOG")
1869 && FindPermission(root.get(), "android.permission.READ_CONTACTS")) {
1870 PrintPermission("android.permission.READ_CALL_LOG",
1871 "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
1872 }
1873
1874 if (!FindPermission(root.get(), "android.permission.WRITE_CALL_LOG")
1875 && FindPermission(root.get(), "android.permission.WRITE_CONTACTS")) {
1876 PrintPermission("android.permission.WRITE_CALL_LOG",
1877 "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
1878 }
1879 }
1880
1881 // If the app hasn't declared the touchscreen as a feature requirement (either
1882 // directly or implied, required or not), then the faketouch feature is implied.
1883 if (!common_feature_group->HasFeature("android.hardware.touchscreen")) {
1884 common_feature_group->addImpliedFeature("android.hardware.faketouch",
1885 "default feature for all apps", false);
1886 }
1887
1888 // Only print the common feature group if no feature group is defined
1889 std::vector<FeatureGroup*> feature_groups;
1890 ForEachChild(root.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
1891 if (auto feature_group = ElementCast<FeatureGroup>(el)) {
1892 feature_groups.push_back(feature_group);
1893 }
1894 });
1895
1896 if (feature_groups.empty()) {
1897 common_feature_group->PrintGroup(printer);
1898 } else {
1899 // Merge the common feature group into the feature group
1900 for (auto& feature_group : feature_groups) {
1901 feature_group->open_gles_version = std::max(feature_group->open_gles_version,
1902 common_feature_group->open_gles_version);
1903 feature_group->Merge(common_feature_group);
1904 feature_group->PrintGroup(printer);
1905 }
1906 };
1907
1908 // Collect the component types of the application
1909 std::set<std::string> components;
1910 ForEachChild(root.get(), [&components](ManifestExtractor::Element* el) -> void {
1911 if (ElementCast<Action>(el)) {
1912 auto action = ElementCast<Action>(el);
1913 if (!action->component.empty()) {
1914 components.insert(action->component);
1915 return;
1916 }
1917 }
1918
1919 if (ElementCast<Category>(el)) {
1920 auto category = ElementCast<Category>(el);
1921 if (!category->component.empty()) {
1922 components.insert(category->component);
1923 return;
1924 }
1925 }
1926 });
1927
1928 // Check for the payment component
1929 auto apk = apk_;
1930 ForEachChild(root.get(), [&apk, &components, &diag](ManifestExtractor::Element* el) -> void {
1931 if (auto service = ElementCast<Service>(el)) {
1932 auto host_apdu_action = ElementCast<Action>(FindElement(service,
1933 [&](ManifestExtractor::Element* el) -> bool {
1934 if (auto action = ElementCast<Action>(el)) {
1935 return (action->component == "host-apdu");
1936 }
1937 return false;
1938 }));
1939
1940 auto offhost_apdu_action = ElementCast<Action>(FindElement(service,
1941 [&](ManifestExtractor::Element* el) -> bool {
1942 if (auto action = ElementCast<Action>(el)) {
1943 return (action->component == "offhost-apdu");
1944 }
1945 return false;
1946 }));
1947
1948 ForEachChild(service, [&apk, &components, &diag, &host_apdu_action,
1949 &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
1950 if (auto meta_data = ElementCast<MetaData>(el)) {
1951 if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" && host_apdu_action)
1952 || (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service"
1953 && offhost_apdu_action)) {
1954
1955 // Attempt to load the resource file
Ryan Mitchell2250c932018-10-04 11:07:40 -07001956 if (!meta_data->resource.empty()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001957 return;
1958 }
Ryan Mitchell2250c932018-10-04 11:07:40 -07001959 auto resource = apk->LoadXml(meta_data->resource, diag);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001960 if (!resource) {
1961 return;
1962 }
1963
1964 // Look for the payment category on an <aid-group> element
1965 auto& root = resource.get()->root;
1966 if ((host_apdu_action && root->name == "host-apdu-service")
1967 || (offhost_apdu_action && root->name == "offhost-apdu-service")) {
1968
1969 for (auto& child : root->GetChildElements()) {
1970 if (child->name == "aid-group") {
1971 auto category = FindAttribute(child, CATEGORY_ATTR);
1972 if (category && category->value == "payment") {
1973 components.insert("payment");
1974 return;
1975 }
1976 }
1977 }
1978 }
1979 }
1980 }
1981 });
1982 }
1983 });
1984
1985 // Print the components types if they are present
1986 auto PrintComponent = [&components, &printer](const std::string& component) -> void {
1987 if (components.find(component) != components.end()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001988 printer->Print(StringPrintf("provides-component:'%s'\n", component.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001989 }
1990 };
1991
1992 PrintComponent("app-widget");
1993 PrintComponent("device-admin");
1994 PrintComponent("ime");
1995 PrintComponent("wallpaper");
1996 PrintComponent("accessibility");
1997 PrintComponent("print-service");
1998 PrintComponent("payment");
1999 PrintComponent("search");
2000 PrintComponent("document-provider");
2001 PrintComponent("launcher");
2002 PrintComponent("notification-listener");
2003 PrintComponent("dream");
2004 PrintComponent("camera");
2005 PrintComponent("camera-secure");
2006
2007 // Print presence of main activity
2008 if (components.find("main") != components.end()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002009 printer->Print("main\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002010 }
2011
2012 // Print presence of activities, recivers, and services with no special components
2013 FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
2014 if (auto activity = ElementCast<Activity>(el)) {
2015 if (!activity->has_component_) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002016 printer->Print("other-activities\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002017 return true;
2018 }
2019 }
2020 return false;
2021 });
2022
2023 FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
2024 if (auto receiver = ElementCast<Receiver>(el)) {
2025 if (!receiver->has_component) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002026 printer->Print("other-receivers\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002027 return true;
2028 }
2029 }
2030 return false;
2031 });
2032
2033 FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
2034 if (auto service = ElementCast<Service>(el)) {
2035 if (!service->has_component) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002036 printer->Print("other-services\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002037 return true;
2038 }
2039 }
2040 return false;
2041 });
2042
2043 // Print the supported screens
2044 SupportsScreen* screen = ElementCast<SupportsScreen>(FindElement(root.get(),
2045 [&](ManifestExtractor::Element* el) -> bool {
2046 return ElementCast<SupportsScreen>(el) != nullptr;
2047 }));
2048
2049 if (screen) {
2050 screen->PrintScreens(printer, target_sdk_);
2051 } else {
2052 // Print the default supported screens
2053 SupportsScreen default_screens;
2054 default_screens.PrintScreens(printer, target_sdk_);
2055 }
2056
2057 // Print all the unique locales of the apk
Ryan Mitchell214846d2018-09-19 16:57:01 -07002058 printer->Print("locales:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002059 for (auto& config : locales_) {
2060 if (config.first.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002061 printer->Print(" '--_--'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002062 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002063 printer->Print(StringPrintf(" '%s'", config.first.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002064 }
2065 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07002066 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002067
2068 // Print all the densities locales of the apk
Ryan Mitchell214846d2018-09-19 16:57:01 -07002069 printer->Print("densities:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002070 for (auto& config : densities_) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002071 printer->Print(StringPrintf(" '%d'", config.first));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002072 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07002073 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002074
2075 // Print the supported architectures of the app
2076 std::set<std::string> architectures;
2077 auto it = apk_->GetFileCollection()->Iterator();
2078 while (it->HasNext()) {
2079 auto file_path = it->Next()->GetSource().path;
2080
2081
2082 size_t pos = file_path.find("lib/");
2083 if (pos != std::string::npos) {
2084 file_path = file_path.substr(pos + 4);
2085 pos = file_path.find("/");
2086 if (pos != std::string::npos) {
2087 file_path = file_path.substr(0, pos);
2088 }
2089
2090 architectures.insert(file_path);
2091 }
2092 }
2093
2094 // Determine if the application has multiArch supports
2095 auto has_multi_arch = FindElement(root.get(), [&](ManifestExtractor::Element* el) -> bool {
2096 if (auto application = ElementCast<Application>(el)) {
2097 return application->has_multi_arch;
2098 }
2099 return false;
2100 });
2101
2102 bool output_alt_native_code = false;
2103 // A multiArch package is one that contains 64-bit and
2104 // 32-bit versions of native code and expects 3rd-party
2105 // apps to load these native code libraries. Since most
2106 // 64-bit systems also support 32-bit apps, the apps
2107 // loading this multiArch package's code may be either
2108 if (has_multi_arch) {
2109 // If this is a multiArch package, report the 64-bit
2110 // version only. Then as a separate entry, report the
2111 // rest.
2112 //
2113 // If we report the 32-bit architecture, this APK will
2114 // be installed on a 32-bit device, causing a large waste
2115 // of bandwidth and disk space. This assumes that
2116 // the developer of the multiArch package has also
2117 // made a version that is 32-bit only.
2118 const std::string kIntel64 = "x86_64";
2119 const std::string kArm64 = "arm64-v8a";
2120
2121 auto arch = architectures.find(kIntel64);
2122 if (arch == architectures.end()) {
2123 arch = architectures.find(kArm64);
2124 }
2125
2126 if (arch != architectures.end()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002127 printer->Print(StringPrintf("native-code: '%s'\n", arch->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002128 architectures.erase(arch);
2129 output_alt_native_code = true;
2130 }
2131 }
2132
2133 if (architectures.size() > 0) {
2134 if (output_alt_native_code) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002135 printer->Print("alt-");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002136 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07002137 printer->Print("native-code:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002138 for (auto& arch : architectures) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002139 printer->Print(StringPrintf(" '%s'", arch.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002140 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07002141 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002142 }
2143
2144 return true;
2145}
2146
2147/**
2148 * Returns the element casted to the type if the element is of that type. Otherwise, returns a null
2149 * pointer.
2150 **/
2151template<typename T>
2152T* ElementCast(ManifestExtractor::Element* element) {
2153 if (element == nullptr) {
2154 return nullptr;
2155 }
2156
2157 const std::unordered_map<std::string, bool> kTagCheck = {
2158 {"action", std::is_base_of<Action, T>::value},
2159 {"activity", std::is_base_of<Activity, T>::value},
2160 {"application", std::is_base_of<Application, T>::value},
2161 {"category", std::is_base_of<Category, T>::value},
2162 {"compatible-screens", std::is_base_of<CompatibleScreens, T>::value},
2163 {"feature-group", std::is_base_of<FeatureGroup, T>::value},
2164 {"input-type", std::is_base_of<InputType, T>::value},
2165 {"intent-filter", std::is_base_of<IntentFilter, T>::value},
2166 {"meta-data", std::is_base_of<MetaData, T>::value},
2167 {"manifest", std::is_base_of<Manifest, T>::value},
2168 {"original-package", std::is_base_of<OriginalPackage, T>::value},
2169 {"package-verifier", std::is_base_of<PackageVerifier, T>::value},
2170 {"permission", std::is_base_of<Permission, T>::value},
2171 {"provider", std::is_base_of<Provider, T>::value},
2172 {"receiver", std::is_base_of<Receiver, T>::value},
2173 {"screen", std::is_base_of<Screen, T>::value},
2174 {"service", std::is_base_of<Service, T>::value},
2175 {"supports-gl-texture", std::is_base_of<SupportsGlTexture, T>::value},
2176 {"supports-input", std::is_base_of<SupportsInput, T>::value},
2177 {"supports-screens", std::is_base_of<SupportsScreen, T>::value},
2178 {"uses-configuration", std::is_base_of<UsesConfiguarion, T>::value},
2179 {"uses-feature", std::is_base_of<UsesFeature, T>::value},
2180 {"uses-permission", std::is_base_of<UsesPermission, T>::value},
2181 {"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
2182 {"uses-library", std::is_base_of<UsesLibrary, T>::value},
2183 {"uses-package", std::is_base_of<UsesPackage, T>::value},
Dianne Hackborn813d7502018-10-02 16:59:46 -07002184 {"static-library", std::is_base_of<StaticLibrary, T>::value},
2185 {"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
2186 {"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002187 {"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
2188 };
2189
2190 auto check = kTagCheck.find(element->tag());
2191 if (check != kTagCheck.end() && check->second) {
2192 return static_cast<T*>(element);
2193 }
2194 return nullptr;
2195}
2196
2197template<typename T>
2198std::unique_ptr<T> CreateType() {
2199 return std::move(util::make_unique<T>());
2200}
2201
2202std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
2203 ManifestExtractor* extractor, xml::Element* el) {
2204 const std::unordered_map<std::string,
2205 std::function<std::unique_ptr<ManifestExtractor::Element>()>>
2206 kTagCheck = {
2207 {"action", &CreateType<Action>},
2208 {"activity", &CreateType<Activity>},
2209 {"application", &CreateType<Application>},
2210 {"category", &CreateType<Category>},
2211 {"compatible-screens", &CreateType<CompatibleScreens>},
2212 {"feature-group", &CreateType<FeatureGroup>},
2213 {"input-type", &CreateType<InputType>},
2214 {"intent-filter",&CreateType<IntentFilter>},
2215 {"manifest", &CreateType<Manifest>},
2216 {"meta-data", &CreateType<MetaData>},
2217 {"original-package", &CreateType<OriginalPackage>},
2218 {"package-verifier", &CreateType<PackageVerifier>},
2219 {"permission", &CreateType<Permission>},
2220 {"provider", &CreateType<Provider>},
2221 {"receiver", &CreateType<Receiver>},
2222 {"screen", &CreateType<Screen>},
2223 {"service", &CreateType<Service>},
2224 {"supports-gl-texture", &CreateType<SupportsGlTexture>},
2225 {"supports-input", &CreateType<SupportsInput>},
2226 {"supports-screens", &CreateType<SupportsScreen>},
2227 {"uses-configuration", &CreateType<UsesConfiguarion>},
2228 {"uses-feature", &CreateType<UsesFeature>},
2229 {"uses-permission", &CreateType<UsesPermission>},
2230 {"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
2231 {"uses-library", &CreateType<UsesLibrary>},
Dianne Hackborn813d7502018-10-02 16:59:46 -07002232 {"static-library", &CreateType<StaticLibrary>},
2233 {"uses-static-library", &CreateType<UsesStaticLibrary>},
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002234 {"uses-package", &CreateType<UsesPackage>},
Dianne Hackborn813d7502018-10-02 16:59:46 -07002235 {"additional-certificate", &CreateType<AdditionalCertificate>},
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002236 {"uses-sdk", &CreateType<UsesSdkBadging>},
2237 };
2238
2239 // Attempt to map the xml tag to a element inflater
2240 std::unique_ptr<ManifestExtractor::Element> element;
2241 auto check = kTagCheck.find(el->name);
2242 if (check != kTagCheck.end()) {
2243 element = check->second();
2244 } else {
2245 element = util::make_unique<ManifestExtractor::Element>();
2246 }
2247
2248 element->extractor_ = extractor;
2249 element->tag_ = el->name;
2250 element->Extract(el);
2251 return element;
2252}
2253
2254std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(xml::Element* el) {
2255 auto element = ManifestExtractor::Element::Inflate(this, el);
2256 parent_stack_.insert(parent_stack_.begin(), element.get());
2257
2258 // Process the element and recursively visit the children
2259 for (xml::Element* child : el->GetChildElements()) {
2260 auto v = Visit(child);
2261 element->AddChild(v);
2262 }
2263
2264 parent_stack_.erase(parent_stack_.begin());
2265 return element;
2266}
2267
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002268
Ryan Mitchell214846d2018-09-19 16:57:01 -07002269int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
2270 IDiagnostics* diag) {
2271 ManifestExtractor extractor(apk, options);
2272 return extractor.Dump(printer, diag);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002273}
2274
Mårten Kongstad24c9aa62018-06-20 08:46:41 +02002275} // namespace aapt