blob: 40bbb36337bc051697959dc222f66af6296c5613 [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,
Anton Hanssoncd2d8e22018-12-11 13:52:17 +000046 PRIORITY_ATTR = 0x0101001c,
Ryan Mitchellfc225b22018-08-21 14:52:51 -070047 RESOURCE_ATTR = 0x01010025,
48 DEBUGGABLE_ATTR = 0x0101000f,
Anton Hanssoncd2d8e22018-12-11 13:52:17 +000049 TARGET_PACKAGE_ATTR = 0x01010021,
Ryan Mitchellfc225b22018-08-21 14:52:51 -070050 VALUE_ATTR = 0x01010024,
51 VERSION_CODE_ATTR = 0x0101021b,
52 VERSION_NAME_ATTR = 0x0101021c,
53 SCREEN_ORIENTATION_ATTR = 0x0101001e,
54 MIN_SDK_VERSION_ATTR = 0x0101020c,
55 MAX_SDK_VERSION_ATTR = 0x01010271,
56 REQ_TOUCH_SCREEN_ATTR = 0x01010227,
57 REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
58 REQ_HARD_KEYBOARD_ATTR = 0x01010229,
59 REQ_NAVIGATION_ATTR = 0x0101022a,
60 REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
61 TARGET_SDK_VERSION_ATTR = 0x01010270,
62 TEST_ONLY_ATTR = 0x01010272,
63 ANY_DENSITY_ATTR = 0x0101026c,
64 GL_ES_VERSION_ATTR = 0x01010281,
65 SMALL_SCREEN_ATTR = 0x01010284,
66 NORMAL_SCREEN_ATTR = 0x01010285,
67 LARGE_SCREEN_ATTR = 0x01010286,
68 XLARGE_SCREEN_ATTR = 0x010102bf,
69 REQUIRED_ATTR = 0x0101028e,
70 INSTALL_LOCATION_ATTR = 0x010102b7,
71 SCREEN_SIZE_ATTR = 0x010102ca,
72 SCREEN_DENSITY_ATTR = 0x010102cb,
73 REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
74 COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
75 LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
76 PUBLIC_KEY_ATTR = 0x010103a6,
77 CATEGORY_ATTR = 0x010103e8,
78 BANNER_ATTR = 0x10103f2,
79 ISGAME_ATTR = 0x10103f4,
Dianne Hackborn813d7502018-10-02 16:59:46 -070080 VERSION_ATTR = 0x01010519,
81 CERT_DIGEST_ATTR = 0x01010548,
Sergey Nikolaienkov91331e52020-09-30 12:58:47 +000082 REQUIRED_FEATURE_ATTR = 0x01010554,
83 REQUIRED_NOT_FEATURE_ATTR = 0x01010555,
Anton Hanssoncd2d8e22018-12-11 13:52:17 +000084 IS_STATIC_ATTR = 0x0101055a,
85 REQUIRED_SYSTEM_PROPERTY_NAME_ATTR = 0x01010565,
86 REQUIRED_SYSTEM_PROPERTY_VALUE_ATTR = 0x01010566,
Ryan Mitchellfc225b22018-08-21 14:52:51 -070087 COMPILE_SDK_VERSION_ATTR = 0x01010572,
88 COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573,
Dianne Hackborn813d7502018-10-02 16:59:46 -070089 VERSION_MAJOR_ATTR = 0x01010577,
90 PACKAGE_TYPE_ATTR = 0x01010587,
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -060091 USES_PERMISSION_FLAGS_ATTR = 0x01010644,
Ryan Mitchellfc225b22018-08-21 14:52:51 -070092};
93
94const std::string& kAndroidNamespace = "http://schemas.android.com/apk/res/android";
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -060095constexpr int kNeverForLocation = 0x00010000;
Ryan Mitchellfc225b22018-08-21 14:52:51 -070096
97/** Retrieves the attribute of the element with the specified attribute resource id. */
98static xml::Attribute* FindAttribute(xml::Element *el, uint32_t resd_id) {
99 for (auto& a : el->attributes) {
100 if (a.compiled_attribute && a.compiled_attribute.value().id) {
101 if (a.compiled_attribute.value().id.value() == resd_id) {
102 return std::move(&a);
103 }
104 }
105 }
106 return nullptr;
107}
108
109/** Retrieves the attribute of the element that has the specified namespace and attribute name. */
110static xml::Attribute* FindAttribute(xml::Element *el, const std::string &package,
111 const std::string &name) {
112 return el->FindAttribute(package, name);
113}
114
115class CommonFeatureGroup;
116
117class ManifestExtractor {
118 public:
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700119
Ryan Mitchell214846d2018-09-19 16:57:01 -0700120 explicit ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options)
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700121 : apk_(apk), options_(options) { }
122
123 class Element {
124 public:
125 Element() = default;
126 virtual ~Element() = default;
127
128 static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
129
130 /** Writes out the extracted contents of the element. */
Ryan Mitchell214846d2018-09-19 16:57:01 -0700131 virtual void Print(text::Printer* printer) { }
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700132
133 /** Adds an element to the list of children of the element. */
134 void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); }
135
Ryan Mitchell1966e1f2021-05-03 13:46:56 -0700136 template <typename Predicate>
137 void Filter(Predicate&& func) {
138 children_.erase(std::remove_if(children_.begin(), children_.end(),
Kelvin Zhang3965584d2021-05-10 12:17:14 -0400139 [&](const auto& e) { return func(e.get()); }),
140 children_.end());
Ryan Mitchell1966e1f2021-05-03 13:46:56 -0700141 }
142
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700143 /** Retrieves the list of children of the element. */
144 const std::vector<std::unique_ptr<Element>>& children() const {
145 return children_;
146 }
147
148 /** Retrieves the extracted xml element tag. */
149 const std::string tag() const {
150 return tag_;
151 }
152
153 protected:
154 ManifestExtractor* extractor() const {
155 return extractor_;
156 }
157
158 /** Retrieves and stores the information extracted from the xml element. */
159 virtual void Extract(xml::Element* el) { }
160
161 /*
162 * Retrieves a configuration value of the resource entry that best matches the specified
163 * configuration.
164 */
165 static Value* BestConfigValue(ResourceEntry* entry,
166 const ConfigDescription& match) {
167 if (!entry) {
168 return nullptr;
169 }
170
171 // Determine the config that best matches the desired config
172 ResourceConfigValue* best_value = nullptr;
173 for (auto& value : entry->values) {
174 if (!value->config.match(match)) {
175 continue;
176 }
177
178 if (best_value != nullptr) {
179 if (!value->config.isBetterThan(best_value->config, &match)) {
180 if (value->config.compare(best_value->config) != 0) {
181 continue;
182 }
183 }
184 }
185
186 best_value = value.get();
187 }
188
189 // The entry has no values
190 if (!best_value) {
191 return nullptr;
192 }
193
194 return best_value->value.get();
195 }
196
197 /** Retrieves the resource assigned to the specified resource id if one exists. */
198 Value* FindValueById(const ResourceTable* table, const ResourceId& res_id,
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700199 const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700200 if (table) {
201 for (auto& package : table->packages) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700202 for (auto& type : package->types) {
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700203 for (auto& entry : type->entries) {
204 if (entry->id && entry->id.value() == res_id.id) {
205 if (auto value = BestConfigValue(entry.get(), config)) {
206 return value;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700207 }
208 }
209 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700210 }
211 }
212 }
213 return nullptr;
214 }
215
216 /** Attempts to resolve the reference to a non-reference value. */
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700217 Value* ResolveReference(Reference* ref, const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700218 const int kMaxIterations = 40;
219 int i = 0;
220 while (ref && ref->id && i++ < kMaxIterations) {
221 auto table = extractor_->apk_->GetResourceTable();
222 if (auto value = FindValueById(table, ref->id.value(), config)) {
223 if (ValueCast<Reference>(value)) {
224 ref = ValueCast<Reference>(value);
225 } else {
226 return value;
227 }
228 }
229 }
230 return nullptr;
231 }
232
233 /**
234 * Retrieves the integer value of the attribute . If the value of the attribute is a reference,
235 * this will attempt to resolve the reference to an integer value.
236 **/
237 int32_t* GetAttributeInteger(xml::Attribute* attr,
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700238 const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700239 if (attr != nullptr) {
240 if (attr->compiled_value) {
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700241 // Resolve references using the configuration
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700242 Value* value = attr->compiled_value.get();
243 if (ValueCast<Reference>(value)) {
244 value = ResolveReference(ValueCast<Reference>(value), config);
245 } else {
246 value = attr->compiled_value.get();
247 }
248 // Retrieve the integer data if possible
249 if (value != nullptr) {
250 if (BinaryPrimitive* intValue = ValueCast<BinaryPrimitive>(value)) {
251 return (int32_t*) &intValue->value.data;
252 }
253 }
254 }
255 }
256 return nullptr;
257 }
258
259 /**
260 * A version of GetAttributeInteger that returns a default integer if the attribute does not
261 * exist or cannot be resolved to an integer value.
262 **/
263 int32_t GetAttributeIntegerDefault(xml::Attribute* attr, int32_t def,
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700264 const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700265 auto value = GetAttributeInteger(attr, config);
266 if (value) {
267 return *value;
268 }
269 return def;
270 }
271
272 /**
273 * Retrieves the string value of the attribute. If the value of the attribute is a reference,
274 * this will attempt to resolve the reference to a string value.
275 **/
276 const std::string* GetAttributeString(xml::Attribute* attr,
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700277 const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700278 if (attr != nullptr) {
279 if (attr->compiled_value) {
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700280 // Resolve references using the configuration
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700281 Value* value = attr->compiled_value.get();
282 if (ValueCast<Reference>(value)) {
283 value = ResolveReference(ValueCast<Reference>(value), config);
284 } else {
285 value = attr->compiled_value.get();
286 }
287
288 // Retrieve the string data of the value if possible
289 if (value != nullptr) {
290 if (String* intValue = ValueCast<String>(value)) {
291 return &(*intValue->value);
292 } else if (RawString* rawValue = ValueCast<RawString>(value)) {
293 return &(*rawValue->value);
294 } else if (FileReference* strValue = ValueCast<FileReference>(value)) {
295 return &(*strValue->path);
296 }
297 }
298 }
Ryan Mitchella36cc982019-06-05 10:13:41 -0700299
300 if (!attr->value.empty()) {
301 return &attr->value;
302 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700303 }
304 return nullptr;
305 }
306
307 /**
308 * A version of GetAttributeString that returns a default string if the attribute does not
309 * exist or cannot be resolved to an string value.
310 **/
311 std::string GetAttributeStringDefault(xml::Attribute* attr, std::string def,
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700312 const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700313 auto value = GetAttributeString(attr, config);
314 if (value) {
315 return *value;
316 }
317 return def;
318 }
319
320 private:
321 ManifestExtractor* extractor_;
322 std::vector<std::unique_ptr<Element>> children_;
323 std::string tag_;
324 };
325
326 friend Element;
327
328 /** Creates a default configuration used to retrieve resources. */
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700329 static ConfigDescription DefaultConfig() {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700330 ConfigDescription config;
331 config.orientation = android::ResTable_config::ORIENTATION_PORT;
332 config.density = android::ResTable_config::DENSITY_MEDIUM;
Jackal Guo201a60a2021-08-31 12:37:30 +0800333 config.sdkVersion = SDK_CUR_DEVELOPMENT; // Very high.
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700334 config.screenWidthDp = 320;
335 config.screenHeightDp = 480;
336 config.smallestScreenWidthDp = 320;
337 config.screenLayout |= android::ResTable_config::SCREENSIZE_NORMAL;
338 return config;
339 }
340
Ryan Mitchell214846d2018-09-19 16:57:01 -0700341 bool Dump(text::Printer* printer, IDiagnostics* diag);
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700342
343 /** Recursively visit the xml element tree and return a processed badging element tree. */
344 std::unique_ptr<Element> Visit(xml::Element* element);
345
346 /** Raises the target sdk value if the min target is greater than the current target. */
347 void RaiseTargetSdk(int32_t min_target) {
348 if (min_target > target_sdk_) {
349 target_sdk_ = min_target;
350 }
351 }
352
353 /**
354 * Retrieves the default feature group that features are added into when <uses-feature>
355 * are not in a <feature-group> element.
356 **/
357 CommonFeatureGroup* GetCommonFeatureGroup() {
358 return commonFeatureGroup_.get();
359 }
360
361 /**
362 * Retrieves a mapping of density values to Configurations for retrieving resources that would be
363 * used for that density setting.
364 **/
365 const std::map<uint16_t, ConfigDescription> densities() const {
366 return densities_;
367 }
368
369 /**
370 * Retrieves a mapping of locale BCP 47 strings to Configurations for retrieving resources that
371 * would be used for that locale setting.
372 **/
373 const std::map<std::string, ConfigDescription> locales() const {
374 return locales_;
375 }
376
377 /** Retrieves the current stack of parent during data extraction. */
378 const std::vector<Element*> parent_stack() const {
379 return parent_stack_;
380 }
381
382 int32_t target_sdk() const {
383 return target_sdk_;
384 }
385
386 LoadedApk* const apk_;
Ryan Mitchell214846d2018-09-19 16:57:01 -0700387 DumpManifestOptions& options_;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700388
389 private:
390 std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
391 std::map<std::string, ConfigDescription> locales_;
392 std::map<uint16_t, ConfigDescription> densities_;
393 std::vector<Element*> parent_stack_;
394 int32_t target_sdk_ = 0;
395};
396
397template<typename T> T* ElementCast(ManifestExtractor::Element* element);
398
399/** Recurs through the children of the specified root in depth-first order. */
400static void ForEachChild(ManifestExtractor::Element* root,
401 std::function<void(ManifestExtractor::Element*)> f) {
402 for (auto& child : root->children()) {
403 f(child.get());
404 ForEachChild(child.get(), f);
405 }
406}
407
408/**
409 * Checks the element and its recursive children for an element that makes the specified
410 * conditional function return true. Returns the first element that makes the conditional function
411 * return true.
412 **/
413static ManifestExtractor::Element* FindElement(ManifestExtractor::Element* root,
414 std::function<bool(ManifestExtractor::Element*)> f) {
415 if (f(root)) {
416 return root;
417 }
418 for (auto& child : root->children()) {
419 if (auto b2 = FindElement(child.get(), f)) {
420 return b2;
421 }
422 }
423 return nullptr;
424}
425
426/** Represents the <manifest> elements **/
427class Manifest : public ManifestExtractor::Element {
428 public:
429 Manifest() = default;
430 std::string package;
431 int32_t versionCode;
432 std::string versionName;
433 const std::string* split = nullptr;
434 const std::string* platformVersionName = nullptr;
435 const std::string* platformVersionCode = nullptr;
Ryan Mitchella36cc982019-06-05 10:13:41 -0700436 const int32_t* platformVersionNameInt = nullptr;
437 const int32_t* platformVersionCodeInt = nullptr;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700438 const int32_t* compilesdkVersion = nullptr;
439 const std::string* compilesdkVersionCodename = nullptr;
440 const int32_t* installLocation = nullptr;
441
442 void Extract(xml::Element* manifest) override {
443 package = GetAttributeStringDefault(FindAttribute(manifest, {}, "package"), "");
444 versionCode = GetAttributeIntegerDefault(FindAttribute(manifest, VERSION_CODE_ATTR), 0);
445 versionName = GetAttributeStringDefault(FindAttribute(manifest, VERSION_NAME_ATTR), "");
446 split = GetAttributeString(FindAttribute(manifest, {}, "split"));
447
448 // Extract the platform build info
449 platformVersionName = GetAttributeString(FindAttribute(manifest, {},
450 "platformBuildVersionName"));
451 platformVersionCode = GetAttributeString(FindAttribute(manifest, {},
452 "platformBuildVersionCode"));
Ryan Mitchella36cc982019-06-05 10:13:41 -0700453 platformVersionNameInt = GetAttributeInteger(FindAttribute(manifest, {},
454 "platformBuildVersionName"));
455 platformVersionCodeInt = GetAttributeInteger(FindAttribute(manifest, {},
456 "platformBuildVersionCode"));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700457
458 // Extract the compile sdk info
459 compilesdkVersion = GetAttributeInteger(FindAttribute(manifest, COMPILE_SDK_VERSION_ATTR));
460 compilesdkVersionCodename = GetAttributeString(
461 FindAttribute(manifest, COMPILE_SDK_VERSION_CODENAME_ATTR));
462 installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR));
463 }
464
Ryan Mitchell214846d2018-09-19 16:57:01 -0700465 void Print(text::Printer* printer) override {
466 printer->Print(StringPrintf("package: name='%s' ", package.data()));
467 printer->Print(StringPrintf("versionCode='%s' ",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700468 (versionCode > 0) ? std::to_string(versionCode).data() : ""));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700469 printer->Print(StringPrintf("versionName='%s'", versionName.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700470
471 if (split) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700472 printer->Print(StringPrintf(" split='%s'", split->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700473 }
474 if (platformVersionName) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700475 printer->Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
Dave Ingram7e0e4c12019-08-01 15:11:41 -0700476 } else if (platformVersionNameInt) {
Ryan Mitchella36cc982019-06-05 10:13:41 -0700477 printer->Print(StringPrintf(" platformBuildVersionName='%d'", *platformVersionNameInt));
478 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700479 if (platformVersionCode) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700480 printer->Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
Dave Ingram7e0e4c12019-08-01 15:11:41 -0700481 } else if (platformVersionCodeInt) {
Ryan Mitchella36cc982019-06-05 10:13:41 -0700482 printer->Print(StringPrintf(" platformBuildVersionCode='%d'", *platformVersionCodeInt));
483 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700484 if (compilesdkVersion) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700485 printer->Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700486 }
487 if (compilesdkVersionCodename) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700488 printer->Print(StringPrintf(" compileSdkVersionCodename='%s'",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700489 compilesdkVersionCodename->data()));
490 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700491 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700492
493 if (installLocation) {
494 switch (*installLocation) {
495 case 0:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700496 printer->Print("install-location:'auto'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700497 break;
498 case 1:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700499 printer->Print("install-location:'internalOnly'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700500 break;
501 case 2:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700502 printer->Print("install-location:'preferExternal'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700503 break;
504 default:
505 break;
506 }
507 }
508 }
509};
510
511/** Represents <application> elements. **/
512class Application : public ManifestExtractor::Element {
513 public:
514 Application() = default;
515 std::string label;
516 std::string icon;
517 std::string banner;
518 int32_t is_game;
519 int32_t debuggable;
520 int32_t test_only;
521 bool has_multi_arch;
522
523 /** Mapping from locales to app names. */
524 std::map<std::string, std::string> locale_labels;
525
526 /** Mapping from densities to app icons. */
527 std::map<uint16_t, std::string> density_icons;
528
529 void Extract(xml::Element* element) override {
530 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
531 icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
532 test_only = GetAttributeIntegerDefault(FindAttribute(element, TEST_ONLY_ATTR), 0);
533 banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
534 is_game = GetAttributeIntegerDefault(FindAttribute(element, ISGAME_ATTR), 0);
535 debuggable = GetAttributeIntegerDefault(FindAttribute(element, DEBUGGABLE_ATTR), 0);
536
537 // We must search by name because the multiArch flag hasn't been API
538 // frozen yet.
539 has_multi_arch = (GetAttributeIntegerDefault(
540 FindAttribute(element, kAndroidNamespace, "multiArch"), 0) != 0);
541
542 // Retrieve the app names for every locale the app supports
543 auto attr = FindAttribute(element, LABEL_ATTR);
544 for (auto& config : extractor()->locales()) {
545 if (auto label = GetAttributeString(attr, config.second)) {
546 if (label) {
547 locale_labels.insert(std::make_pair(config.first, *label));
548 }
549 }
550 }
551
552 // Retrieve the icons for the densities the app supports
553 attr = FindAttribute(element, ICON_ATTR);
554 for (auto& config : extractor()->densities()) {
555 if (auto resource = GetAttributeString(attr, config.second)) {
556 if (resource) {
557 density_icons.insert(std::make_pair(config.first, *resource));
558 }
559 }
560 }
561 }
562
Ryan Mitchell214846d2018-09-19 16:57:01 -0700563 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700564 // Print the labels for every locale
565 for (auto p : locale_labels) {
566 if (p.first.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700567 printer->Print(StringPrintf("application-label:'%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700568 android::ResTable::normalizeForOutput(p.second.data())
569 .c_str()));
570 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700571 printer->Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(),
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700572 android::ResTable::normalizeForOutput(p.second.data())
573 .c_str()));
574 }
575 }
576
577 // Print the icon paths for every density
578 for (auto p : density_icons) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700579 printer->Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700580 }
581
582 // Print the application info
Ryan Mitchell214846d2018-09-19 16:57:01 -0700583 printer->Print(StringPrintf("application: label='%s' ",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700584 android::ResTable::normalizeForOutput(label.data()).c_str()));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700585 printer->Print(StringPrintf("icon='%s'", icon.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700586 if (!banner.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700587 printer->Print(StringPrintf(" banner='%s'", banner.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700588 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700589 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700590
591 if (test_only != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700592 printer->Print(StringPrintf("testOnly='%d'\n", test_only));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700593 }
594 if (is_game != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700595 printer->Print("application-isGame\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700596 }
597 if (debuggable != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700598 printer->Print("application-debuggable\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700599 }
600 }
601};
602
603/** Represents <uses-sdk> elements. **/
604class UsesSdkBadging : public ManifestExtractor::Element {
605 public:
606 UsesSdkBadging() = default;
607 const int32_t* min_sdk = nullptr;
608 const std::string* min_sdk_name = nullptr;
609 const int32_t* max_sdk = nullptr;
610 const int32_t* target_sdk = nullptr;
611 const std::string* target_sdk_name = nullptr;
612
613 void Extract(xml::Element* element) override {
614 min_sdk = GetAttributeInteger(FindAttribute(element, MIN_SDK_VERSION_ATTR));
615 min_sdk_name = GetAttributeString(FindAttribute(element, MIN_SDK_VERSION_ATTR));
616 max_sdk = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
617 target_sdk = GetAttributeInteger(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
618 target_sdk_name = GetAttributeString(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
619
620 // Detect the target sdk of the element
621 if ((min_sdk_name && *min_sdk_name == "Donut")
622 || (target_sdk_name && *target_sdk_name == "Donut")) {
Jackal Guo201a60a2021-08-31 12:37:30 +0800623 extractor()->RaiseTargetSdk(SDK_DONUT);
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700624 }
625 if (min_sdk) {
626 extractor()->RaiseTargetSdk(*min_sdk);
627 }
628 if (target_sdk) {
629 extractor()->RaiseTargetSdk(*target_sdk);
Ryan Mitchell95f02422020-04-30 10:25:53 -0700630 } else if (target_sdk_name) {
Jackal Guo201a60a2021-08-31 12:37:30 +0800631 extractor()->RaiseTargetSdk(SDK_CUR_DEVELOPMENT);
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700632 }
633 }
634
Ryan Mitchell214846d2018-09-19 16:57:01 -0700635 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700636 if (min_sdk) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700637 printer->Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700638 } else if (min_sdk_name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700639 printer->Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700640 }
641 if (max_sdk) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700642 printer->Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700643 }
644 if (target_sdk) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700645 printer->Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700646 } else if (target_sdk_name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700647 printer->Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700648 }
649 }
650};
651
652/** Represents <uses-configuration> elements. **/
653class UsesConfiguarion : public ManifestExtractor::Element {
654 public:
655 UsesConfiguarion() = default;
656 int32_t req_touch_screen = 0;
657 int32_t req_keyboard_type = 0;
658 int32_t req_hard_keyboard = 0;
659 int32_t req_navigation = 0;
660 int32_t req_five_way_nav = 0;
661
662 void Extract(xml::Element* element) override {
663 req_touch_screen = GetAttributeIntegerDefault(
664 FindAttribute(element, REQ_TOUCH_SCREEN_ATTR), 0);
665 req_keyboard_type = GetAttributeIntegerDefault(
666 FindAttribute(element, REQ_KEYBOARD_TYPE_ATTR), 0);
667 req_hard_keyboard = GetAttributeIntegerDefault(
668 FindAttribute(element, REQ_HARD_KEYBOARD_ATTR), 0);
669 req_navigation = GetAttributeIntegerDefault(
670 FindAttribute(element, REQ_NAVIGATION_ATTR), 0);
671 req_five_way_nav = GetAttributeIntegerDefault(
672 FindAttribute(element, REQ_FIVE_WAY_NAV_ATTR), 0);
673 }
674
Ryan Mitchell214846d2018-09-19 16:57:01 -0700675 void Print(text::Printer* printer) override {
676 printer->Print("uses-configuration:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700677 if (req_touch_screen != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700678 printer->Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700679 }
680 if (req_keyboard_type != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700681 printer->Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700682 }
683 if (req_hard_keyboard != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700684 printer->Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700685 }
686 if (req_navigation != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700687 printer->Print(StringPrintf(" reqNavigation='%d'", req_navigation));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700688 }
689 if (req_five_way_nav != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700690 printer->Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700691 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700692 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700693 }
694};
695
696/** Represents <supports-screen> elements. **/
697class SupportsScreen : public ManifestExtractor::Element {
698 public:
699 SupportsScreen() = default;
700 int32_t small_screen = 1;
701 int32_t normal_screen = 1;
702 int32_t large_screen = 1;
703 int32_t xlarge_screen = 1;
704 int32_t any_density = 1;
705 int32_t requires_smallest_width_dp = 0;
706 int32_t compatible_width_limit_dp = 0;
707 int32_t largest_width_limit_dp = 0;
708
709 void Extract(xml::Element* element) override {
710 small_screen = GetAttributeIntegerDefault(FindAttribute(element, SMALL_SCREEN_ATTR), 1);
711 normal_screen = GetAttributeIntegerDefault(FindAttribute(element, NORMAL_SCREEN_ATTR), 1);
712 large_screen = GetAttributeIntegerDefault(FindAttribute(element, LARGE_SCREEN_ATTR), 1);
713 xlarge_screen = GetAttributeIntegerDefault(FindAttribute(element, XLARGE_SCREEN_ATTR), 1);
714 any_density = GetAttributeIntegerDefault(FindAttribute(element, ANY_DENSITY_ATTR), 1);
715
716 requires_smallest_width_dp = GetAttributeIntegerDefault(
717 FindAttribute(element, REQUIRES_SMALLEST_WIDTH_DP_ATTR), 0);
718 compatible_width_limit_dp = GetAttributeIntegerDefault(
719 FindAttribute(element, COMPATIBLE_WIDTH_LIMIT_DP_ATTR), 0);
720 largest_width_limit_dp = GetAttributeIntegerDefault(
721 FindAttribute(element, LARGEST_WIDTH_LIMIT_DP_ATTR), 0);
722
723 // For modern apps, if screen size buckets haven't been specified
724 // but the new width ranges have, then infer the buckets from them.
725 if (small_screen > 0 && normal_screen > 0 && large_screen > 0 && xlarge_screen > 0
726 && requires_smallest_width_dp > 0) {
727 int32_t compat_width = (compatible_width_limit_dp > 0) ? compatible_width_limit_dp
728 : requires_smallest_width_dp;
729 small_screen = (requires_smallest_width_dp <= 240 && compat_width >= 240) ? -1 : 0;
730 normal_screen = (requires_smallest_width_dp <= 320 && compat_width >= 320) ? -1 : 0;
731 large_screen = (requires_smallest_width_dp <= 480 && compat_width >= 480) ? -1 : 0;
732 xlarge_screen = (requires_smallest_width_dp <= 720 && compat_width >= 720) ? -1 : 0;
733 }
734 }
735
Ryan Mitchell214846d2018-09-19 16:57:01 -0700736 void PrintScreens(text::Printer* printer, int32_t target_sdk) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700737 int32_t small_screen_temp = small_screen;
738 int32_t normal_screen_temp = normal_screen;
739 int32_t large_screen_temp = large_screen;
740 int32_t xlarge_screen_temp = xlarge_screen;
741 int32_t any_density_temp = any_density;
742
743 // Determine default values for any unspecified screen sizes,
744 // based on the target SDK of the package. As of 4 (donut)
745 // the screen size support was introduced, so all default to
746 // enabled.
747 if (small_screen_temp > 0) {
Jackal Guo201a60a2021-08-31 12:37:30 +0800748 small_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700749 }
750 if (normal_screen_temp > 0) {
751 normal_screen_temp = -1;
752 }
753 if (large_screen_temp > 0) {
Jackal Guo201a60a2021-08-31 12:37:30 +0800754 large_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700755 }
756 if (xlarge_screen_temp > 0) {
757 // Introduced in Gingerbread.
Jackal Guo201a60a2021-08-31 12:37:30 +0800758 xlarge_screen_temp = target_sdk >= SDK_GINGERBREAD ? -1 : 0;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700759 }
760 if (any_density_temp > 0) {
Jackal Guo201a60a2021-08-31 12:37:30 +0800761 any_density_temp = (target_sdk >= SDK_DONUT || requires_smallest_width_dp > 0 ||
762 compatible_width_limit_dp > 0)
763 ? -1
764 : 0;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700765 }
766
767 // Print the formatted screen info
Ryan Mitchell214846d2018-09-19 16:57:01 -0700768 printer->Print("supports-screens:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700769 if (small_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700770 printer->Print(" 'small'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700771 }
772 if (normal_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700773 printer->Print(" 'normal'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700774 }
775 if (large_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700776 printer->Print(" 'large'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700777 }
778 if (xlarge_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700779 printer->Print(" 'xlarge'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700780 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700781 printer->Print("\n");
782 printer->Print(StringPrintf("supports-any-density: '%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700783 (any_density_temp ) ? "true" : "false"));
784 if (requires_smallest_width_dp > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700785 printer->Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700786 }
787 if (compatible_width_limit_dp > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700788 printer->Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700789 }
790 if (largest_width_limit_dp > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700791 printer->Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700792 }
793 }
794};
795
796/** Represents <feature-group> elements. **/
797class FeatureGroup : public ManifestExtractor::Element {
798 public:
799 FeatureGroup() = default;
800 std::string label;
801 int32_t open_gles_version = 0;
802
803 void Extract(xml::Element* element) override {
804 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
805 }
806
Ryan Mitchell214846d2018-09-19 16:57:01 -0700807 virtual void PrintGroup(text::Printer* printer) {
808 printer->Print(StringPrintf("feature-group: label='%s'\n", label.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700809 if (open_gles_version > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700810 printer->Print(StringPrintf(" uses-gl-es: '0x%x'\n", open_gles_version));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700811 }
812
813 for (auto feature : features_) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700814 printer->Print(StringPrintf(" uses-feature%s: name='%s'",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700815 (feature.second.required ? "" : "-not-required"),
816 feature.first.data()));
817 if (feature.second.version > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700818 printer->Print(StringPrintf(" version='%d'", feature.second.version));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700819 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700820 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700821 }
822 }
823
824 /** Adds a feature to the feature group. */
825 void AddFeature(const std::string& name, bool required = true, int32_t version = -1) {
826 features_.insert(std::make_pair(name, Feature{ required, version }));
827 if (required) {
828 if (name == "android.hardware.camera.autofocus" ||
829 name == "android.hardware.camera.flash") {
830 AddFeature("android.hardware.camera", true);
831 } else if (name == "android.hardware.location.gps" ||
832 name == "android.hardware.location.network") {
833 AddFeature("android.hardware.location", true);
834 } else if (name == "android.hardware.faketouch.multitouch") {
835 AddFeature("android.hardware.faketouch", true);
836 } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
837 name == "android.hardware.faketouch.multitouch.jazzhands") {
838 AddFeature("android.hardware.faketouch.multitouch", true);
839 AddFeature("android.hardware.faketouch", true);
840 } else if (name == "android.hardware.touchscreen.multitouch") {
841 AddFeature("android.hardware.touchscreen", true);
842 } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
843 name == "android.hardware.touchscreen.multitouch.jazzhands") {
844 AddFeature("android.hardware.touchscreen.multitouch", true);
845 AddFeature("android.hardware.touchscreen", true);
846 } else if (name == "android.hardware.opengles.aep") {
847 const int kOpenGLESVersion31 = 0x00030001;
848 if (kOpenGLESVersion31 > open_gles_version) {
849 open_gles_version = kOpenGLESVersion31;
850 }
851 }
852 }
853 }
854
855 /** Returns true if the feature group has the given feature. */
856 virtual bool HasFeature(const std::string& name) {
857 return features_.find(name) != features_.end();
858 }
859
860 /** Merges the features of another feature group into this group. */
861 void Merge(FeatureGroup* group) {
862 open_gles_version = std::max(open_gles_version, group->open_gles_version);
863 for (auto& feature : group->features_) {
864 features_.insert(feature);
865 }
866 }
867
868 protected:
869 struct Feature {
870 public:
871 bool required = false;
872 int32_t version = -1;
873 };
874
875 /* Mapping of feature names to their properties. */
876 std::map<std::string, Feature> features_;
877};
878
879/**
880 * Represents the default feature group for the application if no <feature-group> elements are
881 * present in the manifest.
882 **/
883class CommonFeatureGroup : public FeatureGroup {
884 public:
885 CommonFeatureGroup() = default;
Ryan Mitchell214846d2018-09-19 16:57:01 -0700886 void PrintGroup(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700887 FeatureGroup::PrintGroup(printer);
888
889 // Also print the implied features
890 for (auto feature : implied_features_) {
891 if (features_.find(feature.first) == features_.end()) {
892 const char* sdk23 = feature.second.implied_from_sdk_k23 ? "-sdk-23" : "";
Ryan Mitchell214846d2018-09-19 16:57:01 -0700893 printer->Print(StringPrintf(" uses-feature%s: name='%s'\n", sdk23, feature.first.data()));
894 printer->Print(StringPrintf(" uses-implied-feature%s: name='%s' reason='", sdk23,
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700895 feature.first.data()));
896
897 // Print the reasons as a sentence
898 size_t count = 0;
899 for (auto reason : feature.second.reasons) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700900 printer->Print(reason);
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700901 if (count + 2 < feature.second.reasons.size()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700902 printer->Print(", ");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700903 } else if (count + 1 < feature.second.reasons.size()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700904 printer->Print(", and ");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700905 }
906 count++;
907 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700908 printer->Print("'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700909 }
910 }
911 }
912
913 /** Returns true if the feature group has the given feature. */
914 bool HasFeature(const std::string& name) override {
915 return FeatureGroup::HasFeature(name)
916 || implied_features_.find(name) != implied_features_.end();
917 }
918
919 /** Adds a feature to a set of implied features not explicitly requested in the manifest. */
920 void addImpliedFeature(const std::string& name, const std::string& reason, bool sdk23 = false) {
921 auto entry = implied_features_.find(name);
922 if (entry == implied_features_.end()) {
923 implied_features_.insert(std::make_pair(name, ImpliedFeature(sdk23)));
924 entry = implied_features_.find(name);
925 }
926
927 // A non-sdk 23 implied feature takes precedence.
928 if (entry->second.implied_from_sdk_k23 && !sdk23) {
929 entry->second.implied_from_sdk_k23 = false;
930 }
931
932 entry->second.reasons.insert(reason);
933 }
934
935 /**
936 * Adds a feature to a set of implied features for all features that are implied by the presence
937 * of the permission.
938 **/
939 void addImpliedFeaturesForPermission(int32_t targetSdk, const std::string& name, bool sdk23) {
940 if (name == "android.permission.CAMERA") {
941 addImpliedFeature("android.hardware.camera",
942 StringPrintf("requested %s permission", name.data()),
943 sdk23);
944
945 } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
946 if (targetSdk < SDK_LOLLIPOP) {
947 addImpliedFeature("android.hardware.location.gps",
948 StringPrintf("requested %s permission", name.data()),
949 sdk23);
950 addImpliedFeature("android.hardware.location.gps",
951 StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
952 sdk23);
953 }
954 addImpliedFeature("android.hardware.location",
955 StringPrintf("requested %s permission", name.data()),
956 sdk23);
957
958 } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
959 if (targetSdk < SDK_LOLLIPOP) {
960 addImpliedFeature("android.hardware.location.network",
961 StringPrintf("requested %s permission", name.data()),
962 sdk23);
963 addImpliedFeature("android.hardware.location.network",
964 StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
965 sdk23);
966 }
967 addImpliedFeature("android.hardware.location",
968 StringPrintf("requested %s permission", name.data()),
969 sdk23);
970
971 } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
972 name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
973 name == "android.permission.INSTALL_LOCATION_PROVIDER") {
974 addImpliedFeature("android.hardware.location",
975 StringPrintf("requested %s permission", name.data()),
976 sdk23);
977
978 } else if (name == "android.permission.BLUETOOTH" ||
979 name == "android.permission.BLUETOOTH_ADMIN") {
980 if (targetSdk > SDK_DONUT) {
981 addImpliedFeature("android.hardware.bluetooth",
982 StringPrintf("requested %s permission", name.data()),
983 sdk23);
984 addImpliedFeature("android.hardware.bluetooth",
985 StringPrintf("targetSdkVersion > %d", SDK_DONUT),
986 sdk23);
987 }
988
989 } else if (name == "android.permission.RECORD_AUDIO") {
990 addImpliedFeature("android.hardware.microphone",
991 StringPrintf("requested %s permission", name.data()),
992 sdk23);
993
994 } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
995 name == "android.permission.CHANGE_WIFI_STATE" ||
996 name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
997 addImpliedFeature("android.hardware.wifi",
998 StringPrintf("requested %s permission", name.data()),
999 sdk23);
1000
1001 } else if (name == "android.permission.CALL_PHONE" ||
1002 name == "android.permission.CALL_PRIVILEGED" ||
1003 name == "android.permission.MODIFY_PHONE_STATE" ||
1004 name == "android.permission.PROCESS_OUTGOING_CALLS" ||
1005 name == "android.permission.READ_SMS" ||
1006 name == "android.permission.RECEIVE_SMS" ||
1007 name == "android.permission.RECEIVE_MMS" ||
1008 name == "android.permission.RECEIVE_WAP_PUSH" ||
1009 name == "android.permission.SEND_SMS" ||
1010 name == "android.permission.WRITE_APN_SETTINGS" ||
1011 name == "android.permission.WRITE_SMS") {
1012 addImpliedFeature("android.hardware.telephony",
1013 "requested a telephony permission",
1014 sdk23);
1015 }
1016 }
1017
1018 private:
1019 /**
1020 * Represents a feature that has been automatically added due to a pre-requisite or for some
1021 * other reason.
1022 */
1023 struct ImpliedFeature {
1024 explicit ImpliedFeature(bool sdk23 = false) : implied_from_sdk_k23(sdk23) {}
1025
1026 /** List of human-readable reasons for why this feature was implied. */
1027 std::set<std::string> reasons;
1028
1029 // Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)
1030 bool implied_from_sdk_k23;
1031 };
1032
1033 /* Mapping of implied feature names to their properties. */
1034 std::map<std::string, ImpliedFeature> implied_features_;
1035};
1036
1037/** Represents <uses-feature> elements. **/
1038class UsesFeature : public ManifestExtractor::Element {
1039 public:
1040 UsesFeature() = default;
1041 void Extract(xml::Element* element) override {
1042 const std::string* name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1043 int32_t* gl = GetAttributeInteger(FindAttribute(element, GL_ES_VERSION_ATTR));
1044 bool required = GetAttributeIntegerDefault(
1045 FindAttribute(element, REQUIRED_ATTR), true) != 0;
1046 int32_t version = GetAttributeIntegerDefault(
1047 FindAttribute(element, kAndroidNamespace, "version"), 0);
1048
1049 // Add the feature to the parent feature group element if one exists; otherwise, add it to the
1050 // common feature group
1051 FeatureGroup* feature_group = ElementCast<FeatureGroup>(extractor()->parent_stack()[0]);
1052 if (!feature_group) {
1053 feature_group = extractor()->GetCommonFeatureGroup();
1054 } else {
1055 // All features in side of <feature-group> elements are required.
1056 required = true;
1057 }
1058
1059 if (name) {
1060 feature_group->AddFeature(*name, required, version);
1061 } else if (gl) {
1062 feature_group->open_gles_version = std::max(feature_group->open_gles_version, *gl);
1063 }
1064 }
1065};
1066
1067/** Represents <uses-permission> elements. **/
1068class UsesPermission : public ManifestExtractor::Element {
1069 public:
1070 UsesPermission() = default;
1071 std::string name;
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00001072 std::vector<std::string> requiredFeatures;
1073 std::vector<std::string> requiredNotFeatures;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001074 int32_t required = true;
1075 int32_t maxSdkVersion = -1;
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -06001076 int32_t usesPermissionFlags = 0;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001077
1078 void Extract(xml::Element* element) override {
1079 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00001080 std::string feature =
1081 GetAttributeStringDefault(FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
1082 if (!feature.empty()) {
1083 requiredFeatures.push_back(feature);
1084 }
1085 feature = GetAttributeStringDefault(FindAttribute(element, REQUIRED_NOT_FEATURE_ATTR), "");
1086 if (!feature.empty()) {
1087 requiredNotFeatures.push_back(feature);
1088 }
1089
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001090 required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
1091 maxSdkVersion = GetAttributeIntegerDefault(
1092 FindAttribute(element, MAX_SDK_VERSION_ATTR), -1);
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -06001093 usesPermissionFlags = GetAttributeIntegerDefault(
1094 FindAttribute(element, USES_PERMISSION_FLAGS_ATTR), 0);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001095
1096 if (!name.empty()) {
1097 CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
1098 common->addImpliedFeaturesForPermission(extractor()->target_sdk(), name, false);
1099 }
1100 }
1101
Ryan Mitchell214846d2018-09-19 16:57:01 -07001102 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001103 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001104 printer->Print(StringPrintf("uses-permission: name='%s'", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001105 if (maxSdkVersion >= 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001106 printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001107 }
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -06001108 if ((usesPermissionFlags & kNeverForLocation) != 0) {
1109 printer->Print(StringPrintf(" usesPermissionFlags='neverForLocation'"));
1110 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001111 printer->Print("\n");
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00001112 for (const std::string& requiredFeature : requiredFeatures) {
1113 printer->Print(StringPrintf(" required-feature='%s'\n", requiredFeature.data()));
1114 }
1115 for (const std::string& requiredNotFeature : requiredNotFeatures) {
1116 printer->Print(StringPrintf(" required-not-feature='%s'\n", requiredNotFeature.data()));
1117 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001118 if (required == 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001119 printer->Print(StringPrintf("optional-permission: name='%s'", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001120 if (maxSdkVersion >= 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001121 printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001122 }
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -06001123 if ((usesPermissionFlags & kNeverForLocation) != 0) {
1124 printer->Print(StringPrintf(" usesPermissionFlags='neverForLocation'"));
1125 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001126 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001127 }
1128 }
1129 }
1130
Ryan Mitchell214846d2018-09-19 16:57:01 -07001131 void PrintImplied(text::Printer* printer, const std::string& reason) {
1132 printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001133 if (maxSdkVersion >= 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001134 printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001135 }
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -06001136 if ((usesPermissionFlags & kNeverForLocation) != 0) {
1137 printer->Print(StringPrintf(" usesPermissionFlags='neverForLocation'"));
1138 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001139 printer->Print(StringPrintf(" reason='%s'\n", reason.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001140 }
1141};
1142
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00001143/** Represents <required-feature> elements. **/
1144class RequiredFeature : public ManifestExtractor::Element {
1145 public:
1146 RequiredFeature() = default;
1147 std::string name;
1148
1149 void Extract(xml::Element* element) override {
1150 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1151 auto parent_stack = extractor()->parent_stack();
1152 if (!name.empty() && ElementCast<UsesPermission>(parent_stack[0])) {
1153 UsesPermission* uses_permission = ElementCast<UsesPermission>(parent_stack[0]);
1154 uses_permission->requiredFeatures.push_back(name);
1155 }
1156 }
1157};
1158
1159/** Represents <required-not-feature> elements. **/
1160class RequiredNotFeature : public ManifestExtractor::Element {
1161 public:
1162 RequiredNotFeature() = default;
1163 std::string name;
1164
1165 void Extract(xml::Element* element) override {
1166 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1167 auto parent_stack = extractor()->parent_stack();
1168 if (!name.empty() && ElementCast<UsesPermission>(parent_stack[0])) {
1169 UsesPermission* uses_permission = ElementCast<UsesPermission>(parent_stack[0]);
1170 uses_permission->requiredNotFeatures.push_back(name);
1171 }
1172 }
1173};
1174
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001175/** Represents <uses-permission-sdk-23> elements. **/
1176class UsesPermissionSdk23 : public ManifestExtractor::Element {
1177 public:
1178 UsesPermissionSdk23() = default;
1179 const std::string* name = nullptr;
1180 const int32_t* maxSdkVersion = nullptr;
1181
1182 void Extract(xml::Element* element) override {
1183 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1184 maxSdkVersion = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
1185
1186 if (name) {
1187 CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
1188 common->addImpliedFeaturesForPermission(extractor()->target_sdk(), *name, true);
1189 }
1190 }
1191
Ryan Mitchell214846d2018-09-19 16:57:01 -07001192 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001193 if (name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001194 printer->Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001195 if (maxSdkVersion) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001196 printer->Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001197 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001198 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001199 }
1200 }
1201};
1202
1203/** Represents <permission> elements. These elements are only printing when dumping permissions. **/
1204class Permission : public ManifestExtractor::Element {
1205 public:
1206 Permission() = default;
1207 std::string name;
1208
1209 void Extract(xml::Element* element) override {
1210 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1211 }
1212
Ryan Mitchell214846d2018-09-19 16:57:01 -07001213 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001214 if (extractor()->options_.only_permissions && !name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001215 printer->Print(StringPrintf("permission: %s\n", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001216 }
1217 }
1218};
1219
1220/** Represents <activity> elements. **/
1221class Activity : public ManifestExtractor::Element {
1222 public:
1223 Activity() = default;
1224 std::string name;
1225 std::string icon;
1226 std::string label;
1227 std::string banner;
1228
1229 bool has_component_ = false;
1230 bool has_launcher_category = false;
1231 bool has_leanback_launcher_category = false;
1232 bool has_main_action = false;
1233
1234 void Extract(xml::Element* element) override {
1235 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1236 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
1237 icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
1238 banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
1239
1240 // Retrieve the package name from the manifest
1241 std::string package;
1242 for (auto& parent : extractor()->parent_stack()) {
1243 if (auto manifest = ElementCast<Manifest>(parent)) {
1244 package = manifest->package;
1245 break;
1246 }
1247 }
1248
1249 // Fully qualify the activity name
Chih-Hung Hsiehf2ef6572020-02-11 14:27:11 -08001250 ssize_t idx = name.find('.');
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001251 if (idx == 0) {
1252 name = package + name;
1253 } else if (idx < 0) {
1254 name = package + "." + name;
1255 }
1256
1257 auto orientation = GetAttributeInteger(FindAttribute(element, SCREEN_ORIENTATION_ATTR));
1258 if (orientation) {
1259 CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
1260 int orien = *orientation;
1261 if (orien == 0 || orien == 6 || orien == 8) {
1262 // Requests landscape, sensorLandscape, or reverseLandscape.
1263 common->addImpliedFeature("android.hardware.screen.landscape",
1264 "one or more activities have specified a landscape orientation",
1265 false);
1266 } else if (orien == 1 || orien == 7 || orien == 9) {
1267 // Requests portrait, sensorPortrait, or reversePortrait.
1268 common->addImpliedFeature("android.hardware.screen.portrait",
1269 "one or more activities have specified a portrait orientation",
1270 false);
1271 }
1272 }
1273 }
1274
Ryan Mitchell214846d2018-09-19 16:57:01 -07001275 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001276 // Print whether the activity has the HOME category and a the MAIN action
1277 if (has_main_action && has_launcher_category) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001278 printer->Print("launchable-activity:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001279 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001280 printer->Print(StringPrintf(" name='%s' ", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001281 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001282 printer->Print(StringPrintf(" label='%s' icon='%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001283 android::ResTable::normalizeForOutput(label.data()).c_str(),
1284 icon.data()));
1285 }
1286
1287 // Print wether the activity has the HOME category and a the MAIN action
1288 if (has_leanback_launcher_category) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001289 printer->Print("leanback-launchable-activity:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001290 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001291 printer->Print(StringPrintf(" name='%s' ", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001292 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001293 printer->Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001294 android::ResTable::normalizeForOutput(label.data()).c_str(),
1295 icon.data(), banner.data()));
1296 }
1297 }
1298};
1299
1300/** Represents <intent-filter> elements. */
1301class IntentFilter : public ManifestExtractor::Element {
1302 public:
1303 IntentFilter() = default;
1304};
1305
1306/** Represents <category> elements. */
1307class Category : public ManifestExtractor::Element {
1308 public:
1309 Category() = default;
1310 std::string component = "";
1311
1312 void Extract(xml::Element* element) override {
1313 const std::string* category = GetAttributeString(FindAttribute(element, NAME_ATTR));
1314
1315 auto parent_stack = extractor()->parent_stack();
1316 if (category && ElementCast<IntentFilter>(parent_stack[0])
1317 && ElementCast<Activity>(parent_stack[1])) {
1318 Activity* activity = ElementCast<Activity>(parent_stack[1]);
1319
1320 if (*category == "android.intent.category.LAUNCHER") {
1321 activity->has_launcher_category = true;
1322 } else if (*category == "android.intent.category.LEANBACK_LAUNCHER") {
1323 activity->has_leanback_launcher_category = true;
1324 } else if (*category == "android.intent.category.HOME") {
1325 component = "launcher";
1326 }
1327 }
1328 }
1329};
1330
1331/**
1332 * Represents <provider> elements. The elements may have an <intent-filter> which may have <action>
1333 * elements nested within.
1334 **/
1335class Provider : public ManifestExtractor::Element {
1336 public:
1337 Provider() = default;
1338 bool has_required_saf_attributes = false;
1339
1340 void Extract(xml::Element* element) override {
1341 const int32_t* exported = GetAttributeInteger(FindAttribute(element, EXPORTED_ATTR));
1342 const int32_t* grant_uri_permissions = GetAttributeInteger(
1343 FindAttribute(element, GRANT_URI_PERMISSIONS_ATTR));
1344 const std::string* permission = GetAttributeString(
1345 FindAttribute(element, PERMISSION_ATTR));
1346
1347 has_required_saf_attributes = ((exported && *exported != 0)
1348 && (grant_uri_permissions && *grant_uri_permissions != 0)
1349 && (permission && *permission == "android.permission.MANAGE_DOCUMENTS"));
1350 }
1351};
1352
1353/** Represents <receiver> elements. **/
1354class Receiver : public ManifestExtractor::Element {
1355 public:
1356 Receiver() = default;
1357 const std::string* permission = nullptr;
1358 bool has_component = false;
1359
1360 void Extract(xml::Element* element) override {
1361 permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
1362 }
1363};
1364
1365/**Represents <service> elements. **/
1366class Service : public ManifestExtractor::Element {
1367 public:
1368 Service() = default;
1369 const std::string* permission = nullptr;
1370 bool has_component = false;
1371
1372 void Extract(xml::Element* element) override {
1373 permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
1374 }
1375};
1376
1377/** Represents <uses-library> elements. **/
1378class UsesLibrary : public ManifestExtractor::Element {
1379 public:
1380 UsesLibrary() = default;
1381 std::string name;
1382 int required;
1383
1384 void Extract(xml::Element* element) override {
1385 auto parent_stack = extractor()->parent_stack();
1386 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1387 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1388 required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
1389 }
1390 }
1391
Ryan Mitchell214846d2018-09-19 16:57:01 -07001392 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001393 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001394 printer->Print(StringPrintf("uses-library%s:'%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001395 (required == 0) ? "-not-required" : "", name.data()));
1396 }
1397 }
1398};
1399
Dianne Hackborn813d7502018-10-02 16:59:46 -07001400/** Represents <static-library> elements. **/
1401class StaticLibrary : public ManifestExtractor::Element {
1402 public:
1403 StaticLibrary() = default;
1404 std::string name;
1405 int version;
1406 int versionMajor;
1407
1408 void Extract(xml::Element* element) override {
1409 auto parent_stack = extractor()->parent_stack();
1410 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1411 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1412 version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
1413 versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
1414 }
1415 }
1416
Ryan Mitchell214846d2018-09-19 16:57:01 -07001417 void Print(text::Printer* printer) override {
1418 printer->Print(StringPrintf(
Dianne Hackborn813d7502018-10-02 16:59:46 -07001419 "static-library: name='%s' version='%d' versionMajor='%d'\n",
1420 name.data(), version, versionMajor));
1421 }
1422};
1423
1424/** Represents <uses-static-library> elements. **/
1425class UsesStaticLibrary : public ManifestExtractor::Element {
1426 public:
1427 UsesStaticLibrary() = default;
1428 std::string name;
1429 int version;
1430 int versionMajor;
1431 std::vector<std::string> certDigests;
1432
1433 void Extract(xml::Element* element) override {
1434 auto parent_stack = extractor()->parent_stack();
1435 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1436 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1437 version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
1438 versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
1439 AddCertDigest(element);
1440 }
1441 }
1442
1443 void AddCertDigest(xml::Element* element) {
1444 std::string digest = GetAttributeStringDefault(FindAttribute(element, CERT_DIGEST_ATTR), "");
1445 // We allow ":" delimiters in the SHA declaration as this is the format
1446 // emitted by the certtool making it easy for developers to copy/paste.
1447 digest.erase(std::remove(digest.begin(), digest.end(), ':'), digest.end());
1448 if (!digest.empty()) {
1449 certDigests.push_back(digest);
1450 }
1451 }
1452
Ryan Mitchell214846d2018-09-19 16:57:01 -07001453 void Print(text::Printer* printer) override {
1454 printer->Print(StringPrintf(
Dianne Hackborn813d7502018-10-02 16:59:46 -07001455 "uses-static-library: name='%s' version='%d' versionMajor='%d'",
1456 name.data(), version, versionMajor));
1457 for (size_t i = 0; i < certDigests.size(); i++) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001458 printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
Dianne Hackborn813d7502018-10-02 16:59:46 -07001459 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001460 printer->Print("\n");
Dianne Hackborn813d7502018-10-02 16:59:46 -07001461 }
1462};
1463
Jiyong Park6a5b8b12020-06-30 13:23:36 +09001464/** Represents <uses-native-library> elements. **/
1465class UsesNativeLibrary : public ManifestExtractor::Element {
1466 public:
1467 UsesNativeLibrary() = default;
1468 std::string name;
1469 int required;
1470
1471 void Extract(xml::Element* element) override {
1472 auto parent_stack = extractor()->parent_stack();
1473 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1474 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1475 required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
1476 }
1477 }
1478
1479 void Print(text::Printer* printer) override {
1480 if (!name.empty()) {
1481 printer->Print(StringPrintf("uses-native-library%s:'%s'\n",
1482 (required == 0) ? "-not-required" : "", name.data()));
1483 }
1484 }
1485};
1486
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001487/**
1488 * Represents <meta-data> elements. These tags are only printed when a flag is passed in to
1489 * explicitly enable meta data printing.
1490 **/
1491class MetaData : public ManifestExtractor::Element {
1492 public:
1493 MetaData() = default;
1494 std::string name;
Ryan Mitchell2250c932018-10-04 11:07:40 -07001495 std::string value;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001496 const int* value_int;
Ryan Mitchell2250c932018-10-04 11:07:40 -07001497 std::string resource;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001498 const int* resource_int;
1499
1500 void Extract(xml::Element* element) override {
1501 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
Ryan Mitchell2250c932018-10-04 11:07:40 -07001502 value = GetAttributeStringDefault(FindAttribute(element, VALUE_ATTR), "");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001503 value_int = GetAttributeInteger(FindAttribute(element, VALUE_ATTR));
Ryan Mitchell2250c932018-10-04 11:07:40 -07001504 resource = GetAttributeStringDefault(FindAttribute(element, RESOURCE_ATTR), "");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001505 resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR));
1506 }
1507
Ryan Mitchell214846d2018-09-19 16:57:01 -07001508 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001509 if (extractor()->options_.include_meta_data && !name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001510 printer->Print(StringPrintf("meta-data: name='%s' ", name.data()));
Ryan Mitchell2250c932018-10-04 11:07:40 -07001511 if (!value.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001512 printer->Print(StringPrintf("value='%s' ", value.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001513 } else if (value_int) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001514 printer->Print(StringPrintf("value='%d' ", *value_int));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001515 } else {
Ryan Mitchell2250c932018-10-04 11:07:40 -07001516 if (!resource.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001517 printer->Print(StringPrintf("resource='%s' ", resource.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001518 } else if (resource_int) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001519 printer->Print(StringPrintf("resource='%d' ", *resource_int));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001520 }
1521 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001522 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001523 }
1524 }
1525};
1526
1527/**
1528 * Represents <action> elements. Detects the presence of certain activity, provider, receiver, and
1529 * service components.
1530 **/
1531class Action : public ManifestExtractor::Element {
1532 public:
1533 Action() = default;
1534 std::string component = "";
1535
1536 void Extract(xml::Element* element) override {
1537 auto parent_stack = extractor()->parent_stack();
1538 std::string action = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1539
1540 if (ElementCast<IntentFilter>(parent_stack[0])) {
1541 if (ElementCast<Activity>(parent_stack[1])) {
1542 // Detects the presence of a particular type of activity.
1543 Activity* activity = ElementCast<Activity>(parent_stack[1]);
1544 auto map = std::map<std::string, std::string>({
1545 { "android.intent.action.MAIN" , "main" },
1546 { "android.intent.action.VIDEO_CAMERA" , "camera" },
1547 { "android.intent.action.STILL_IMAGE_CAMERA_SECURE" , "camera-secure" },
1548 });
1549
1550 auto entry = map.find(action);
1551 if (entry != map.end()) {
1552 component = entry->second;
1553 activity->has_component_ = true;
1554 }
1555
1556 if (action == "android.intent.action.MAIN") {
1557 activity->has_main_action = true;
1558 }
1559
1560 } else if (ElementCast<Receiver>(parent_stack[1])) {
1561 // Detects the presence of a particular type of receiver. If the action requires a
1562 // permission, then the receiver element is checked for the permission.
1563 Receiver* receiver = ElementCast<Receiver>(parent_stack[1]);
1564 auto map = std::map<std::string, std::string>({
1565 { "android.appwidget.action.APPWIDGET_UPDATE" , "app-widget" },
1566 { "android.app.action.DEVICE_ADMIN_ENABLED" , "device-admin" },
1567 });
1568
1569 auto permissions = std::map<std::string, std::string>({
1570 { "android.app.action.DEVICE_ADMIN_ENABLED" , "android.permission.BIND_DEVICE_ADMIN" },
1571 });
1572
1573 auto entry = map.find(action);
1574 auto permission = permissions.find(action);
1575 if (entry != map.end() && (permission == permissions.end()
1576 || (receiver->permission && permission->second == *receiver->permission))) {
1577 receiver->has_component = true;
1578 component = entry->second;
1579 }
1580
1581 } else if (ElementCast<Service>(parent_stack[1])) {
1582 // Detects the presence of a particular type of service. If the action requires a
1583 // permission, then the service element is checked for the permission.
1584 Service* service = ElementCast<Service>(parent_stack[1]);
1585 auto map = std::map<std::string, std::string>({
1586 { "android.view.InputMethod" , "ime" },
1587 { "android.service.wallpaper.WallpaperService" , "wallpaper" },
1588 { "android.accessibilityservice.AccessibilityService" , "accessibility" },
1589 { "android.printservice.PrintService" , "print-service" },
1590 { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" , "host-apdu" },
1591 { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" , "offhost-apdu" },
1592 { "android.service.notification.NotificationListenerService" ,"notification-listener" },
1593 { "android.service.dreams.DreamService" , "dream" },
1594 });
1595
1596 auto permissions = std::map<std::string, std::string>({
1597 { "android.accessibilityservice.AccessibilityService" ,
1598 "android.permission.BIND_ACCESSIBILITY_SERVICE" },
1599 { "android.printservice.PrintService" , "android.permission.BIND_PRINT_SERVICE" },
1600 { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" ,
1601 "android.permission.BIND_NFC_SERVICE" },
1602 { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" ,
1603 "android.permission.BIND_NFC_SERVICE" },
1604 { "android.service.notification.NotificationListenerService" ,
1605 "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" },
1606 { "android.service.dreams.DreamService" , "android.permission.BIND_DREAM_SERVICE" },
1607 });
1608
1609 auto entry = map.find(action);
1610 auto permission = permissions.find(action);
1611 if (entry != map.end() && (permission == permissions.end()
1612 || (service->permission && permission->second == *service->permission))) {
1613 service->has_component= true;
1614 component = entry->second;
1615 }
1616
1617 } else if (ElementCast<Provider>(parent_stack[1])) {
1618 // Detects the presence of a particular type of receiver. If the provider requires a
1619 // permission, then the provider element is checked for the permission.
1620 // Detect whether this action
1621 Provider* provider = ElementCast<Provider>(parent_stack[1]);
1622 if (action == "android.content.action.DOCUMENTS_PROVIDER"
1623 && provider->has_required_saf_attributes) {
1624 component = "document-provider";
1625 }
1626 }
1627 }
1628
1629 // Represents a searchable interface
1630 if (action == "android.intent.action.SEARCH") {
1631 component = "search";
1632 }
1633 }
1634};
1635
1636/**
1637 * Represents <supports-input> elements. The element may have <input-type> elements nested within.
1638 **/
1639class SupportsInput : public ManifestExtractor::Element {
1640 public:
1641 SupportsInput() = default;
1642 std::vector<std::string> inputs;
1643
Ryan Mitchell214846d2018-09-19 16:57:01 -07001644 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001645 const size_t size = inputs.size();
1646 if (size > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001647 printer->Print("supports-input: '");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001648 for (size_t i = 0; i < size; i++) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001649 printer->Print(StringPrintf("value='%s' ", inputs[i].data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001650 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001651 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001652 }
1653 }
1654};
1655
1656/** Represents <input-type> elements. **/
1657class InputType : public ManifestExtractor::Element {
1658 public:
1659 InputType() = default;
1660 void Extract(xml::Element* element) override {
1661 auto name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1662 auto parent_stack = extractor()->parent_stack();
1663
1664 // Add the input to the set of supported inputs
1665 if (name && ElementCast<SupportsInput>(parent_stack[0])) {
1666 SupportsInput* supports = ElementCast<SupportsInput>(parent_stack[0]);
1667 supports->inputs.push_back(*name);
1668 }
1669 }
1670};
1671
1672/** Represents <original-package> elements. **/
1673class OriginalPackage : public ManifestExtractor::Element {
1674 public:
1675 OriginalPackage() = default;
1676 const std::string* name = nullptr;
1677
1678 void Extract(xml::Element* element) override {
1679 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1680 }
1681
Ryan Mitchell214846d2018-09-19 16:57:01 -07001682 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001683 if (name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001684 printer->Print(StringPrintf("original-package:'%s'\n", name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001685 }
1686 }
1687};
1688
Anton Hanssoncd2d8e22018-12-11 13:52:17 +00001689
1690/** Represents <overlay> elements. **/
1691class Overlay : public ManifestExtractor::Element {
1692 public:
1693 Overlay() = default;
1694 const std::string* target_package = nullptr;
1695 int priority;
1696 bool is_static;
1697 const std::string* required_property_name = nullptr;
1698 const std::string* required_property_value = nullptr;
1699
1700 void Extract(xml::Element* element) override {
1701 target_package = GetAttributeString(FindAttribute(element, TARGET_PACKAGE_ATTR));
1702 priority = GetAttributeIntegerDefault(FindAttribute(element, PRIORITY_ATTR), 0);
1703 is_static = GetAttributeIntegerDefault(FindAttribute(element, IS_STATIC_ATTR), false) != 0;
1704 required_property_name = GetAttributeString(
1705 FindAttribute(element, REQUIRED_SYSTEM_PROPERTY_NAME_ATTR));
1706 required_property_value = GetAttributeString(
1707 FindAttribute(element, REQUIRED_SYSTEM_PROPERTY_VALUE_ATTR));
1708 }
1709
1710 void Print(text::Printer* printer) override {
1711 printer->Print(StringPrintf("overlay:"));
1712 if (target_package) {
1713 printer->Print(StringPrintf(" targetPackage='%s'", target_package->c_str()));
1714 }
1715 printer->Print(StringPrintf(" priority='%d'", priority));
1716 printer->Print(StringPrintf(" isStatic='%s'", is_static ? "true" : "false"));
1717 if (required_property_name) {
1718 printer->Print(StringPrintf(" requiredPropertyName='%s'", required_property_name->c_str()));
1719 }
1720 if (required_property_value) {
1721 printer->Print(StringPrintf(" requiredPropertyValue='%s'", required_property_value->c_str()));
1722 }
1723 printer->Print("\n");
1724 }
1725};
1726
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001727/** * Represents <package-verifier> elements. **/
1728class PackageVerifier : public ManifestExtractor::Element {
1729 public:
1730 PackageVerifier() = default;
1731 const std::string* name = nullptr;
1732 const std::string* public_key = nullptr;
1733
1734 void Extract(xml::Element* element) override {
1735 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1736 public_key = GetAttributeString(FindAttribute(element, PUBLIC_KEY_ATTR));
1737 }
1738
Ryan Mitchell214846d2018-09-19 16:57:01 -07001739 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001740 if (name && public_key) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001741 printer->Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001742 name->data(), public_key->data()));
1743 }
1744 }
1745};
1746
1747/** Represents <uses-package> elements. **/
1748class UsesPackage : public ManifestExtractor::Element {
1749 public:
1750 UsesPackage() = default;
Dianne Hackborn813d7502018-10-02 16:59:46 -07001751 const std::string* packageType = nullptr;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001752 const std::string* name = nullptr;
Dianne Hackborn813d7502018-10-02 16:59:46 -07001753 int version;
1754 int versionMajor;
1755 std::vector<std::string> certDigests;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001756
1757 void Extract(xml::Element* element) override {
Dianne Hackborn813d7502018-10-02 16:59:46 -07001758 auto parent_stack = extractor()->parent_stack();
1759 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1760 packageType = GetAttributeString(FindAttribute(element, PACKAGE_TYPE_ATTR));
1761 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1762 version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
1763 versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
1764 AddCertDigest(element);
1765 }
1766 }
1767
1768 void AddCertDigest(xml::Element* element) {
1769 std::string digest = GetAttributeStringDefault(FindAttribute(element, CERT_DIGEST_ATTR), "");
1770 // We allow ":" delimiters in the SHA declaration as this is the format
1771 // emitted by the certtool making it easy for developers to copy/paste.
1772 digest.erase(std::remove(digest.begin(), digest.end(), ':'), digest.end());
1773 if (!digest.empty()) {
1774 certDigests.push_back(digest);
1775 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001776 }
1777
Ryan Mitchell214846d2018-09-19 16:57:01 -07001778 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001779 if (name) {
Dianne Hackborn813d7502018-10-02 16:59:46 -07001780 if (packageType) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001781 printer->Print(StringPrintf(
Dianne Hackborn813d7502018-10-02 16:59:46 -07001782 "uses-typed-package: type='%s' name='%s' version='%d' versionMajor='%d'",
1783 packageType->data(), name->data(), version, versionMajor));
1784 for (size_t i = 0; i < certDigests.size(); i++) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001785 printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
Dianne Hackborn813d7502018-10-02 16:59:46 -07001786 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001787 printer->Print("\n");
Dianne Hackborn813d7502018-10-02 16:59:46 -07001788 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001789 printer->Print(StringPrintf("uses-package:'%s'\n", name->data()));
Dianne Hackborn813d7502018-10-02 16:59:46 -07001790 }
1791 }
1792 }
1793};
1794
1795/** Represents <additional-certificate> elements. **/
1796class AdditionalCertificate : public ManifestExtractor::Element {
1797 public:
1798 AdditionalCertificate() = default;
1799
1800 void Extract(xml::Element* element) override {
1801 auto parent_stack = extractor()->parent_stack();
1802 if (parent_stack.size() > 0) {
1803 if (ElementCast<UsesPackage>(parent_stack[0])) {
1804 UsesPackage* uses = ElementCast<UsesPackage>(parent_stack[0]);
1805 uses->AddCertDigest(element);
1806 } else if (ElementCast<UsesStaticLibrary>(parent_stack[0])) {
1807 UsesStaticLibrary* uses = ElementCast<UsesStaticLibrary>(parent_stack[0]);
1808 uses->AddCertDigest(element);
1809 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001810 }
1811 }
1812};
1813
1814/** Represents <screen> elements found in <compatible-screens> elements. */
1815class Screen : public ManifestExtractor::Element {
1816 public:
1817 Screen() = default;
1818 const int32_t* size = nullptr;
1819 const int32_t* density = nullptr;
1820
1821 void Extract(xml::Element* element) override {
1822 size = GetAttributeInteger(FindAttribute(element, SCREEN_SIZE_ATTR));
1823 density = GetAttributeInteger(FindAttribute(element, SCREEN_DENSITY_ATTR));
1824 }
1825};
1826
1827/**
1828 * Represents <compatible-screens> elements. These elements have <screen> elements nested within
1829 * that each denote a supported screen size and screen density.
1830 **/
1831class CompatibleScreens : public ManifestExtractor::Element {
1832 public:
1833 CompatibleScreens() = default;
Ryan Mitchell214846d2018-09-19 16:57:01 -07001834 void Print(text::Printer* printer) override {
1835 printer->Print("compatible-screens:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001836
1837 bool first = true;
1838 ForEachChild(this, [&printer, &first](ManifestExtractor::Element* el){
1839 if (auto screen = ElementCast<Screen>(el)) {
1840 if (first) {
1841 first = false;
1842 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001843 printer->Print(",");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001844 }
1845
1846 if (screen->size && screen->density) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001847 printer->Print(StringPrintf("'%d/%d'", *screen->size, *screen->density));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001848 }
1849 }
1850 });
Ryan Mitchell214846d2018-09-19 16:57:01 -07001851 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001852 }
1853};
1854
1855/** Represents <supports-gl-texture> elements. **/
1856class SupportsGlTexture : public ManifestExtractor::Element {
1857 public:
1858 SupportsGlTexture() = default;
1859 const std::string* name = nullptr;
1860
1861 void Extract(xml::Element* element) override {
1862 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1863 }
1864
Ryan Mitchell214846d2018-09-19 16:57:01 -07001865 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001866 if (name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001867 printer->Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001868 }
1869 }
1870};
1871
Todd Kennedyce3e1292020-10-29 17:14:24 -07001872/** Represents <property> elements. **/
1873class Property : public ManifestExtractor::Element {
1874 public:
1875 Property() = default;
1876 std::string name;
1877 std::string value;
1878 const int* value_int;
1879 std::string resource;
1880 const int* resource_int;
1881
1882 void Extract(xml::Element* element) override {
1883 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1884 value = GetAttributeStringDefault(FindAttribute(element, VALUE_ATTR), "");
1885 value_int = GetAttributeInteger(FindAttribute(element, VALUE_ATTR));
1886 resource = GetAttributeStringDefault(FindAttribute(element, RESOURCE_ATTR), "");
1887 resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR));
1888 }
1889
1890 void Print(text::Printer* printer) override {
1891 printer->Print(StringPrintf("property: name='%s' ", name.data()));
1892 if (!value.empty()) {
1893 printer->Print(StringPrintf("value='%s' ", value.data()));
1894 } else if (value_int) {
1895 printer->Print(StringPrintf("value='%d' ", *value_int));
1896 } else {
1897 if (!resource.empty()) {
1898 printer->Print(StringPrintf("resource='%s' ", resource.data()));
1899 } else if (resource_int) {
1900 printer->Print(StringPrintf("resource='%d' ", *resource_int));
1901 }
1902 }
1903 printer->Print("\n");
1904 }
1905};
1906
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001907/** Recursively prints the extracted badging element. */
Ryan Mitchell214846d2018-09-19 16:57:01 -07001908static void Print(ManifestExtractor::Element* el, text::Printer* printer) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001909 el->Print(printer);
1910 for (auto &child : el->children()) {
1911 Print(child.get(), printer);
1912 }
1913}
1914
Ryan Mitchell214846d2018-09-19 16:57:01 -07001915bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001916 // Load the manifest
1917 std::unique_ptr<xml::XmlResource> doc = apk_->LoadXml("AndroidManifest.xml", diag);
1918 if (doc == nullptr) {
1919 diag->Error(DiagMessage() << "failed to find AndroidManifest.xml");
1920 return false;
1921 }
1922
1923 xml::Element* element = doc->root.get();
1924 if (element->name != "manifest") {
1925 diag->Error(DiagMessage() << "manifest does not start with <manifest> tag");
1926 return false;
1927 }
1928
1929 // Print only the <uses-permission>, <uses-permission-sdk23>, and <permission> elements if
1930 // printing only permission elements is requested
1931 if (options_.only_permissions) {
1932 std::unique_ptr<ManifestExtractor::Element> manifest_element =
1933 ManifestExtractor::Element::Inflate(this, element);
1934
1935 if (auto manifest = ElementCast<Manifest>(manifest_element.get())) {
1936 for (xml::Element* child : element->GetChildElements()) {
1937 if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
1938 || child->name == "permission") {
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00001939 // Inflate the element and its descendants
1940 auto permission_element = Visit(child);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001941 manifest->AddChild(permission_element);
1942 }
1943 }
1944
Ryan Mitchell214846d2018-09-19 16:57:01 -07001945 printer->Print(StringPrintf("package: %s\n", manifest->package.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001946 ForEachChild(manifest, [&printer](ManifestExtractor::Element* el) -> void {
1947 el->Print(printer);
1948 });
1949
1950 return true;
1951 }
1952
1953 return false;
1954 }
1955
1956 // Collect information about the resource configurations
1957 if (apk_->GetResourceTable()) {
1958 for (auto &package : apk_->GetResourceTable()->packages) {
1959 for (auto &type : package->types) {
1960 for (auto &entry : type->entries) {
1961 for (auto &value : entry->values) {
1962 std::string locale_str = value->config.GetBcp47LanguageTag();
1963
1964 // Collect all the unique locales of the apk
1965 if (locales_.find(locale_str) == locales_.end()) {
Ryan Mitchell4ea90752020-07-31 08:21:43 -07001966 ConfigDescription config = ManifestExtractor::DefaultConfig();
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001967 config.setBcp47Locale(locale_str.data());
1968 locales_.insert(std::make_pair(locale_str, config));
1969 }
1970
1971 // Collect all the unique density of the apk
1972 uint16_t density = (value->config.density == 0) ? (uint16_t) 160
1973 : value->config.density;
1974 if (densities_.find(density) == densities_.end()) {
Ryan Mitchell4ea90752020-07-31 08:21:43 -07001975 ConfigDescription config = ManifestExtractor::DefaultConfig();
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001976 config.density = density;
1977 densities_.insert(std::make_pair(density, config));
1978 }
1979 }
1980 }
1981 }
1982 }
1983 }
1984
1985 // Extract badging information
1986 auto root = Visit(element);
1987
Ryan Mitchell1966e1f2021-05-03 13:46:56 -07001988 // Filter out all "uses-sdk" tags besides the very last tag. The android runtime only uses the
1989 // attribute values from the last defined tag.
1990 std::vector<UsesSdkBadging*> filtered_uses_sdk_tags;
1991 for (const auto& child : root->children()) {
1992 if (auto uses_sdk = ElementCast<UsesSdkBadging>(child.get())) {
1993 filtered_uses_sdk_tags.emplace_back(uses_sdk);
1994 }
1995 }
Ryan Mitchell6ea9ed32021-05-20 11:38:57 -07001996 if (filtered_uses_sdk_tags.size() >= 2U) {
1997 filtered_uses_sdk_tags.pop_back();
1998 root->Filter([&](const ManifestExtractor::Element* e) {
1999 return std::find(filtered_uses_sdk_tags.begin(), filtered_uses_sdk_tags.end(), e) !=
2000 filtered_uses_sdk_tags.end();
2001 });
2002 }
Ryan Mitchell1966e1f2021-05-03 13:46:56 -07002003
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002004 // Print the elements in order seen
2005 Print(root.get(), printer);
2006
2007 /** Recursively checks the extracted elements for the specified permission. **/
2008 auto FindPermission = [&](ManifestExtractor::Element* root,
2009 const std::string& name) -> ManifestExtractor::Element* {
2010 return FindElement(root, [&](ManifestExtractor::Element* el) -> bool {
2011 if (UsesPermission* permission = ElementCast<UsesPermission>(el)) {
2012 return permission->name == name;
2013 }
2014 return false;
2015 });
2016 };
2017
2018 auto PrintPermission = [&printer](const std::string& name, const std::string& reason,
2019 int32_t max_sdk_version) -> void {
2020 auto permission = util::make_unique<UsesPermission>();
2021 permission->name = name;
2022 permission->maxSdkVersion = max_sdk_version;
2023 permission->Print(printer);
2024 permission->PrintImplied(printer, reason);
2025 };
2026
2027 // Implied permissions
2028 // Pre-1.6 implicitly granted permission compatibility logic
2029 CommonFeatureGroup* common_feature_group = GetCommonFeatureGroup();
2030 bool insert_write_external = false;
2031 auto write_external_permission = ElementCast<UsesPermission>(
2032 FindPermission(root.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
2033
Jackal Guo201a60a2021-08-31 12:37:30 +08002034 if (target_sdk() < SDK_DONUT) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002035 if (!write_external_permission) {
2036 PrintPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
2037 insert_write_external = true;
2038 }
2039
2040 if (!FindPermission(root.get(), "android.permission.READ_PHONE_STATE")) {
2041 PrintPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
2042 }
2043 }
2044
2045 // If the application has requested WRITE_EXTERNAL_STORAGE, we will
2046 // force them to always take READ_EXTERNAL_STORAGE as well. We always
2047 // do this (regardless of target API version) because we can't have
2048 // an app with write permission but not read permission.
2049 auto read_external = FindPermission(root.get(), "android.permission.READ_EXTERNAL_STORAGE");
2050 if (!read_external && (insert_write_external || write_external_permission)) {
2051 PrintPermission("android.permission.READ_EXTERNAL_STORAGE",
2052 "requested WRITE_EXTERNAL_STORAGE",
2053 (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
2054 }
2055
2056 // Pre-JellyBean call log permission compatibility.
Jackal Guo201a60a2021-08-31 12:37:30 +08002057 if (target_sdk() < SDK_JELLY_BEAN) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002058 if (!FindPermission(root.get(), "android.permission.READ_CALL_LOG")
2059 && FindPermission(root.get(), "android.permission.READ_CONTACTS")) {
2060 PrintPermission("android.permission.READ_CALL_LOG",
2061 "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
2062 }
2063
2064 if (!FindPermission(root.get(), "android.permission.WRITE_CALL_LOG")
2065 && FindPermission(root.get(), "android.permission.WRITE_CONTACTS")) {
2066 PrintPermission("android.permission.WRITE_CALL_LOG",
2067 "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
2068 }
2069 }
2070
2071 // If the app hasn't declared the touchscreen as a feature requirement (either
2072 // directly or implied, required or not), then the faketouch feature is implied.
2073 if (!common_feature_group->HasFeature("android.hardware.touchscreen")) {
2074 common_feature_group->addImpliedFeature("android.hardware.faketouch",
2075 "default feature for all apps", false);
2076 }
2077
2078 // Only print the common feature group if no feature group is defined
2079 std::vector<FeatureGroup*> feature_groups;
2080 ForEachChild(root.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
2081 if (auto feature_group = ElementCast<FeatureGroup>(el)) {
2082 feature_groups.push_back(feature_group);
2083 }
2084 });
2085
2086 if (feature_groups.empty()) {
2087 common_feature_group->PrintGroup(printer);
2088 } else {
2089 // Merge the common feature group into the feature group
2090 for (auto& feature_group : feature_groups) {
2091 feature_group->open_gles_version = std::max(feature_group->open_gles_version,
2092 common_feature_group->open_gles_version);
2093 feature_group->Merge(common_feature_group);
2094 feature_group->PrintGroup(printer);
2095 }
2096 };
2097
2098 // Collect the component types of the application
2099 std::set<std::string> components;
2100 ForEachChild(root.get(), [&components](ManifestExtractor::Element* el) -> void {
2101 if (ElementCast<Action>(el)) {
2102 auto action = ElementCast<Action>(el);
2103 if (!action->component.empty()) {
2104 components.insert(action->component);
2105 return;
2106 }
2107 }
2108
2109 if (ElementCast<Category>(el)) {
2110 auto category = ElementCast<Category>(el);
2111 if (!category->component.empty()) {
2112 components.insert(category->component);
2113 return;
2114 }
2115 }
2116 });
2117
2118 // Check for the payment component
2119 auto apk = apk_;
2120 ForEachChild(root.get(), [&apk, &components, &diag](ManifestExtractor::Element* el) -> void {
2121 if (auto service = ElementCast<Service>(el)) {
2122 auto host_apdu_action = ElementCast<Action>(FindElement(service,
2123 [&](ManifestExtractor::Element* el) -> bool {
2124 if (auto action = ElementCast<Action>(el)) {
2125 return (action->component == "host-apdu");
2126 }
2127 return false;
2128 }));
2129
2130 auto offhost_apdu_action = ElementCast<Action>(FindElement(service,
2131 [&](ManifestExtractor::Element* el) -> bool {
2132 if (auto action = ElementCast<Action>(el)) {
2133 return (action->component == "offhost-apdu");
2134 }
2135 return false;
2136 }));
2137
2138 ForEachChild(service, [&apk, &components, &diag, &host_apdu_action,
2139 &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
2140 if (auto meta_data = ElementCast<MetaData>(el)) {
2141 if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" && host_apdu_action)
2142 || (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service"
2143 && offhost_apdu_action)) {
2144
2145 // Attempt to load the resource file
Ryan Mitchell2250c932018-10-04 11:07:40 -07002146 if (!meta_data->resource.empty()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002147 return;
2148 }
Ryan Mitchell2250c932018-10-04 11:07:40 -07002149 auto resource = apk->LoadXml(meta_data->resource, diag);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002150 if (!resource) {
2151 return;
2152 }
2153
2154 // Look for the payment category on an <aid-group> element
2155 auto& root = resource.get()->root;
2156 if ((host_apdu_action && root->name == "host-apdu-service")
2157 || (offhost_apdu_action && root->name == "offhost-apdu-service")) {
2158
2159 for (auto& child : root->GetChildElements()) {
2160 if (child->name == "aid-group") {
2161 auto category = FindAttribute(child, CATEGORY_ATTR);
2162 if (category && category->value == "payment") {
2163 components.insert("payment");
2164 return;
2165 }
2166 }
2167 }
2168 }
2169 }
2170 }
2171 });
2172 }
2173 });
2174
2175 // Print the components types if they are present
2176 auto PrintComponent = [&components, &printer](const std::string& component) -> void {
2177 if (components.find(component) != components.end()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002178 printer->Print(StringPrintf("provides-component:'%s'\n", component.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002179 }
2180 };
2181
2182 PrintComponent("app-widget");
2183 PrintComponent("device-admin");
2184 PrintComponent("ime");
2185 PrintComponent("wallpaper");
2186 PrintComponent("accessibility");
2187 PrintComponent("print-service");
2188 PrintComponent("payment");
2189 PrintComponent("search");
2190 PrintComponent("document-provider");
2191 PrintComponent("launcher");
2192 PrintComponent("notification-listener");
2193 PrintComponent("dream");
2194 PrintComponent("camera");
2195 PrintComponent("camera-secure");
2196
2197 // Print presence of main activity
2198 if (components.find("main") != components.end()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002199 printer->Print("main\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002200 }
2201
2202 // Print presence of activities, recivers, and services with no special components
2203 FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
2204 if (auto activity = ElementCast<Activity>(el)) {
2205 if (!activity->has_component_) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002206 printer->Print("other-activities\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002207 return true;
2208 }
2209 }
2210 return false;
2211 });
2212
2213 FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
2214 if (auto receiver = ElementCast<Receiver>(el)) {
2215 if (!receiver->has_component) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002216 printer->Print("other-receivers\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002217 return true;
2218 }
2219 }
2220 return false;
2221 });
2222
2223 FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
2224 if (auto service = ElementCast<Service>(el)) {
2225 if (!service->has_component) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002226 printer->Print("other-services\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002227 return true;
2228 }
2229 }
2230 return false;
2231 });
2232
2233 // Print the supported screens
2234 SupportsScreen* screen = ElementCast<SupportsScreen>(FindElement(root.get(),
2235 [&](ManifestExtractor::Element* el) -> bool {
2236 return ElementCast<SupportsScreen>(el) != nullptr;
2237 }));
2238
2239 if (screen) {
2240 screen->PrintScreens(printer, target_sdk_);
2241 } else {
2242 // Print the default supported screens
2243 SupportsScreen default_screens;
2244 default_screens.PrintScreens(printer, target_sdk_);
2245 }
2246
2247 // Print all the unique locales of the apk
Ryan Mitchell214846d2018-09-19 16:57:01 -07002248 printer->Print("locales:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002249 for (auto& config : locales_) {
2250 if (config.first.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002251 printer->Print(" '--_--'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002252 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002253 printer->Print(StringPrintf(" '%s'", config.first.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002254 }
2255 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07002256 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002257
2258 // Print all the densities locales of the apk
Ryan Mitchell214846d2018-09-19 16:57:01 -07002259 printer->Print("densities:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002260 for (auto& config : densities_) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002261 printer->Print(StringPrintf(" '%d'", config.first));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002262 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07002263 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002264
2265 // Print the supported architectures of the app
2266 std::set<std::string> architectures;
2267 auto it = apk_->GetFileCollection()->Iterator();
2268 while (it->HasNext()) {
2269 auto file_path = it->Next()->GetSource().path;
2270
2271
2272 size_t pos = file_path.find("lib/");
2273 if (pos != std::string::npos) {
2274 file_path = file_path.substr(pos + 4);
Chih-Hung Hsiehf2ef6572020-02-11 14:27:11 -08002275 pos = file_path.find('/');
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002276 if (pos != std::string::npos) {
2277 file_path = file_path.substr(0, pos);
2278 }
2279
2280 architectures.insert(file_path);
2281 }
2282 }
2283
2284 // Determine if the application has multiArch supports
2285 auto has_multi_arch = FindElement(root.get(), [&](ManifestExtractor::Element* el) -> bool {
2286 if (auto application = ElementCast<Application>(el)) {
2287 return application->has_multi_arch;
2288 }
2289 return false;
2290 });
2291
2292 bool output_alt_native_code = false;
2293 // A multiArch package is one that contains 64-bit and
2294 // 32-bit versions of native code and expects 3rd-party
2295 // apps to load these native code libraries. Since most
2296 // 64-bit systems also support 32-bit apps, the apps
2297 // loading this multiArch package's code may be either
2298 if (has_multi_arch) {
2299 // If this is a multiArch package, report the 64-bit
2300 // version only. Then as a separate entry, report the
2301 // rest.
2302 //
2303 // If we report the 32-bit architecture, this APK will
2304 // be installed on a 32-bit device, causing a large waste
2305 // of bandwidth and disk space. This assumes that
2306 // the developer of the multiArch package has also
2307 // made a version that is 32-bit only.
2308 const std::string kIntel64 = "x86_64";
2309 const std::string kArm64 = "arm64-v8a";
2310
2311 auto arch = architectures.find(kIntel64);
2312 if (arch == architectures.end()) {
2313 arch = architectures.find(kArm64);
2314 }
2315
2316 if (arch != architectures.end()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002317 printer->Print(StringPrintf("native-code: '%s'\n", arch->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002318 architectures.erase(arch);
2319 output_alt_native_code = true;
2320 }
2321 }
2322
2323 if (architectures.size() > 0) {
2324 if (output_alt_native_code) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002325 printer->Print("alt-");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002326 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07002327 printer->Print("native-code:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002328 for (auto& arch : architectures) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002329 printer->Print(StringPrintf(" '%s'", arch.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002330 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07002331 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002332 }
2333
2334 return true;
2335}
2336
2337/**
2338 * Returns the element casted to the type if the element is of that type. Otherwise, returns a null
2339 * pointer.
2340 **/
2341template<typename T>
2342T* ElementCast(ManifestExtractor::Element* element) {
2343 if (element == nullptr) {
2344 return nullptr;
2345 }
2346
2347 const std::unordered_map<std::string, bool> kTagCheck = {
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002348 {"action", std::is_base_of<Action, T>::value},
2349 {"activity", std::is_base_of<Activity, T>::value},
2350 {"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
2351 {"application", std::is_base_of<Application, T>::value},
2352 {"category", std::is_base_of<Category, T>::value},
2353 {"compatible-screens", std::is_base_of<CompatibleScreens, T>::value},
2354 {"feature-group", std::is_base_of<FeatureGroup, T>::value},
2355 {"input-type", std::is_base_of<InputType, T>::value},
2356 {"intent-filter", std::is_base_of<IntentFilter, T>::value},
2357 {"meta-data", std::is_base_of<MetaData, T>::value},
2358 {"manifest", std::is_base_of<Manifest, T>::value},
2359 {"original-package", std::is_base_of<OriginalPackage, T>::value},
2360 {"overlay", std::is_base_of<Overlay, T>::value},
2361 {"package-verifier", std::is_base_of<PackageVerifier, T>::value},
2362 {"permission", std::is_base_of<Permission, T>::value},
Todd Kennedyce3e1292020-10-29 17:14:24 -07002363 {"property", std::is_base_of<Property, T>::value},
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002364 {"provider", std::is_base_of<Provider, T>::value},
2365 {"receiver", std::is_base_of<Receiver, T>::value},
2366 {"required-feature", std::is_base_of<RequiredFeature, T>::value},
2367 {"required-not-feature", std::is_base_of<RequiredNotFeature, T>::value},
2368 {"screen", std::is_base_of<Screen, T>::value},
2369 {"service", std::is_base_of<Service, T>::value},
2370 {"static-library", std::is_base_of<StaticLibrary, T>::value},
2371 {"supports-gl-texture", std::is_base_of<SupportsGlTexture, T>::value},
2372 {"supports-input", std::is_base_of<SupportsInput, T>::value},
2373 {"supports-screens", std::is_base_of<SupportsScreen, T>::value},
2374 {"uses-configuration", std::is_base_of<UsesConfiguarion, T>::value},
2375 {"uses-feature", std::is_base_of<UsesFeature, T>::value},
2376 {"uses-library", std::is_base_of<UsesLibrary, T>::value},
2377 {"uses-native-library", std::is_base_of<UsesNativeLibrary, T>::value},
2378 {"uses-package", std::is_base_of<UsesPackage, T>::value},
2379 {"uses-permission", std::is_base_of<UsesPermission, T>::value},
2380 {"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
2381 {"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
2382 {"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002383 };
2384
2385 auto check = kTagCheck.find(element->tag());
2386 if (check != kTagCheck.end() && check->second) {
2387 return static_cast<T*>(element);
2388 }
2389 return nullptr;
2390}
2391
2392template<typename T>
2393std::unique_ptr<T> CreateType() {
2394 return std::move(util::make_unique<T>());
2395}
2396
2397std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
2398 ManifestExtractor* extractor, xml::Element* el) {
2399 const std::unordered_map<std::string,
2400 std::function<std::unique_ptr<ManifestExtractor::Element>()>>
2401 kTagCheck = {
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002402 {"action", &CreateType<Action>},
2403 {"activity", &CreateType<Activity>},
2404 {"additional-certificate", &CreateType<AdditionalCertificate>},
2405 {"application", &CreateType<Application>},
2406 {"category", &CreateType<Category>},
2407 {"compatible-screens", &CreateType<CompatibleScreens>},
2408 {"feature-group", &CreateType<FeatureGroup>},
2409 {"input-type", &CreateType<InputType>},
2410 {"intent-filter", &CreateType<IntentFilter>},
2411 {"manifest", &CreateType<Manifest>},
2412 {"meta-data", &CreateType<MetaData>},
2413 {"original-package", &CreateType<OriginalPackage>},
2414 {"overlay", &CreateType<Overlay>},
2415 {"package-verifier", &CreateType<PackageVerifier>},
2416 {"permission", &CreateType<Permission>},
Todd Kennedyce3e1292020-10-29 17:14:24 -07002417 {"property", &CreateType<Property>},
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002418 {"provider", &CreateType<Provider>},
2419 {"receiver", &CreateType<Receiver>},
2420 {"required-feature", &CreateType<RequiredFeature>},
2421 {"required-not-feature", &CreateType<RequiredNotFeature>},
2422 {"screen", &CreateType<Screen>},
2423 {"service", &CreateType<Service>},
2424 {"static-library", &CreateType<StaticLibrary>},
2425 {"supports-gl-texture", &CreateType<SupportsGlTexture>},
2426 {"supports-input", &CreateType<SupportsInput>},
2427 {"supports-screens", &CreateType<SupportsScreen>},
2428 {"uses-configuration", &CreateType<UsesConfiguarion>},
2429 {"uses-feature", &CreateType<UsesFeature>},
2430 {"uses-library", &CreateType<UsesLibrary>},
2431 {"uses-native-library", &CreateType<UsesNativeLibrary>},
2432 {"uses-package", &CreateType<UsesPackage>},
2433 {"uses-permission", &CreateType<UsesPermission>},
2434 {"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
2435 {"uses-sdk", &CreateType<UsesSdkBadging>},
2436 {"uses-static-library", &CreateType<UsesStaticLibrary>},
2437 };
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002438
2439 // Attempt to map the xml tag to a element inflater
2440 std::unique_ptr<ManifestExtractor::Element> element;
2441 auto check = kTagCheck.find(el->name);
2442 if (check != kTagCheck.end()) {
2443 element = check->second();
2444 } else {
2445 element = util::make_unique<ManifestExtractor::Element>();
2446 }
2447
2448 element->extractor_ = extractor;
2449 element->tag_ = el->name;
2450 element->Extract(el);
2451 return element;
2452}
2453
2454std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(xml::Element* el) {
2455 auto element = ManifestExtractor::Element::Inflate(this, el);
2456 parent_stack_.insert(parent_stack_.begin(), element.get());
2457
2458 // Process the element and recursively visit the children
2459 for (xml::Element* child : el->GetChildElements()) {
2460 auto v = Visit(child);
2461 element->AddChild(v);
2462 }
2463
2464 parent_stack_.erase(parent_stack_.begin());
2465 return element;
2466}
2467
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002468
Ryan Mitchell214846d2018-09-19 16:57:01 -07002469int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
2470 IDiagnostics* diag) {
2471 ManifestExtractor extractor(apk, options);
Ryan Mitchell28c88802019-03-28 11:28:54 -07002472 return extractor.Dump(printer, diag) ? 0 : 1;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002473}
2474
Mårten Kongstad24c9aa62018-06-20 08:46:41 +02002475} // namespace aapt