blob: 64a9441d1ac2f0b12129a2ab48e5141268ff9559 [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>
Iurii Makhnoa9c74c52022-04-12 15:04:12 +000020#include <memory>
21#include <set>
22#include <vector>
Dianne Hackborn813d7502018-10-02 16:59:46 -070023
Ryan Mitchellfc225b22018-08-21 14:52:51 -070024#include "LoadedApk.h"
25#include "SdkConstants.h"
26#include "ValueVisitor.h"
Iurii Makhnoa9c74c52022-04-12 15:04:12 +000027#include "androidfw/ConfigDescription.h"
Ryan Mitchellfc225b22018-08-21 14:52:51 -070028#include "io/File.h"
29#include "io/FileStream.h"
30#include "process/IResourceTableConsumer.h"
31#include "xml/XmlDom.h"
32
33using ::android::base::StringPrintf;
Mårten Kongstad24c9aa62018-06-20 08:46:41 +020034using ::android::ConfigDescription;
Ryan Mitchellfc225b22018-08-21 14:52:51 -070035
36namespace aapt {
37
38/**
39 * These are attribute resource constants for the platform, as found in android.R.attr.
40 */
41enum {
42 LABEL_ATTR = 0x01010001,
43 ICON_ATTR = 0x01010002,
44 NAME_ATTR = 0x01010003,
45 PERMISSION_ATTR = 0x01010006,
46 EXPORTED_ATTR = 0x01010010,
47 GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
Anton Hanssoncd2d8e22018-12-11 13:52:17 +000048 PRIORITY_ATTR = 0x0101001c,
Ryan Mitchellfc225b22018-08-21 14:52:51 -070049 RESOURCE_ATTR = 0x01010025,
50 DEBUGGABLE_ATTR = 0x0101000f,
Anton Hanssoncd2d8e22018-12-11 13:52:17 +000051 TARGET_PACKAGE_ATTR = 0x01010021,
Ryan Mitchellfc225b22018-08-21 14:52:51 -070052 VALUE_ATTR = 0x01010024,
53 VERSION_CODE_ATTR = 0x0101021b,
54 VERSION_NAME_ATTR = 0x0101021c,
55 SCREEN_ORIENTATION_ATTR = 0x0101001e,
56 MIN_SDK_VERSION_ATTR = 0x0101020c,
57 MAX_SDK_VERSION_ATTR = 0x01010271,
58 REQ_TOUCH_SCREEN_ATTR = 0x01010227,
59 REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
60 REQ_HARD_KEYBOARD_ATTR = 0x01010229,
61 REQ_NAVIGATION_ATTR = 0x0101022a,
62 REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
63 TARGET_SDK_VERSION_ATTR = 0x01010270,
64 TEST_ONLY_ATTR = 0x01010272,
65 ANY_DENSITY_ATTR = 0x0101026c,
66 GL_ES_VERSION_ATTR = 0x01010281,
67 SMALL_SCREEN_ATTR = 0x01010284,
68 NORMAL_SCREEN_ATTR = 0x01010285,
69 LARGE_SCREEN_ATTR = 0x01010286,
70 XLARGE_SCREEN_ATTR = 0x010102bf,
71 REQUIRED_ATTR = 0x0101028e,
72 INSTALL_LOCATION_ATTR = 0x010102b7,
73 SCREEN_SIZE_ATTR = 0x010102ca,
74 SCREEN_DENSITY_ATTR = 0x010102cb,
75 REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
76 COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
77 LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
78 PUBLIC_KEY_ATTR = 0x010103a6,
79 CATEGORY_ATTR = 0x010103e8,
80 BANNER_ATTR = 0x10103f2,
81 ISGAME_ATTR = 0x10103f4,
Dianne Hackborn813d7502018-10-02 16:59:46 -070082 VERSION_ATTR = 0x01010519,
83 CERT_DIGEST_ATTR = 0x01010548,
Sergey Nikolaienkov91331e52020-09-30 12:58:47 +000084 REQUIRED_FEATURE_ATTR = 0x01010554,
85 REQUIRED_NOT_FEATURE_ATTR = 0x01010555,
Anton Hanssoncd2d8e22018-12-11 13:52:17 +000086 IS_STATIC_ATTR = 0x0101055a,
87 REQUIRED_SYSTEM_PROPERTY_NAME_ATTR = 0x01010565,
88 REQUIRED_SYSTEM_PROPERTY_VALUE_ATTR = 0x01010566,
Ryan Mitchellfc225b22018-08-21 14:52:51 -070089 COMPILE_SDK_VERSION_ATTR = 0x01010572,
90 COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573,
Dianne Hackborn813d7502018-10-02 16:59:46 -070091 VERSION_MAJOR_ATTR = 0x01010577,
92 PACKAGE_TYPE_ATTR = 0x01010587,
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -060093 USES_PERMISSION_FLAGS_ATTR = 0x01010644,
Ryan Mitchellfc225b22018-08-21 14:52:51 -070094};
95
96const std::string& kAndroidNamespace = "http://schemas.android.com/apk/res/android";
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -060097constexpr int kNeverForLocation = 0x00010000;
Ryan Mitchellfc225b22018-08-21 14:52:51 -070098
99/** Retrieves the attribute of the element with the specified attribute resource id. */
100static xml::Attribute* FindAttribute(xml::Element *el, uint32_t resd_id) {
101 for (auto& a : el->attributes) {
102 if (a.compiled_attribute && a.compiled_attribute.value().id) {
103 if (a.compiled_attribute.value().id.value() == resd_id) {
104 return std::move(&a);
105 }
106 }
107 }
108 return nullptr;
109}
110
111/** Retrieves the attribute of the element that has the specified namespace and attribute name. */
112static xml::Attribute* FindAttribute(xml::Element *el, const std::string &package,
113 const std::string &name) {
114 return el->FindAttribute(package, name);
115}
116
117class CommonFeatureGroup;
Iurii Makhnoa9c74c52022-04-12 15:04:12 +0000118class Architectures;
119class SupportsScreen;
120class FeatureGroup;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700121
122class ManifestExtractor {
123 public:
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700124
Ryan Mitchell214846d2018-09-19 16:57:01 -0700125 explicit ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options)
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700126 : apk_(apk), options_(options) { }
127
128 class Element {
129 public:
130 Element() = default;
131 virtual ~Element() = default;
132
133 static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
134
135 /** Writes out the extracted contents of the element. */
Ryan Mitchell214846d2018-09-19 16:57:01 -0700136 virtual void Print(text::Printer* printer) { }
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700137
138 /** Adds an element to the list of children of the element. */
139 void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); }
140
Ryan Mitchell1966e1f2021-05-03 13:46:56 -0700141 template <typename Predicate>
142 void Filter(Predicate&& func) {
143 children_.erase(std::remove_if(children_.begin(), children_.end(),
Kelvin Zhang3965584d2021-05-10 12:17:14 -0400144 [&](const auto& e) { return func(e.get()); }),
145 children_.end());
Ryan Mitchell1966e1f2021-05-03 13:46:56 -0700146 }
147
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700148 /** Retrieves the list of children of the element. */
149 const std::vector<std::unique_ptr<Element>>& children() const {
150 return children_;
151 }
152
153 /** Retrieves the extracted xml element tag. */
154 const std::string tag() const {
155 return tag_;
156 }
157
158 protected:
159 ManifestExtractor* extractor() const {
160 return extractor_;
161 }
162
163 /** Retrieves and stores the information extracted from the xml element. */
164 virtual void Extract(xml::Element* el) { }
165
166 /*
167 * Retrieves a configuration value of the resource entry that best matches the specified
168 * configuration.
169 */
170 static Value* BestConfigValue(ResourceEntry* entry,
171 const ConfigDescription& match) {
172 if (!entry) {
173 return nullptr;
174 }
175
176 // Determine the config that best matches the desired config
177 ResourceConfigValue* best_value = nullptr;
178 for (auto& value : entry->values) {
179 if (!value->config.match(match)) {
180 continue;
181 }
182
183 if (best_value != nullptr) {
184 if (!value->config.isBetterThan(best_value->config, &match)) {
185 if (value->config.compare(best_value->config) != 0) {
186 continue;
187 }
188 }
189 }
190
191 best_value = value.get();
192 }
193
194 // The entry has no values
195 if (!best_value) {
196 return nullptr;
197 }
198
199 return best_value->value.get();
200 }
201
202 /** Retrieves the resource assigned to the specified resource id if one exists. */
203 Value* FindValueById(const ResourceTable* table, const ResourceId& res_id,
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700204 const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700205 if (table) {
206 for (auto& package : table->packages) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700207 for (auto& type : package->types) {
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700208 for (auto& entry : type->entries) {
209 if (entry->id && entry->id.value() == res_id.id) {
210 if (auto value = BestConfigValue(entry.get(), config)) {
211 return value;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700212 }
213 }
214 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700215 }
216 }
217 }
218 return nullptr;
219 }
220
221 /** Attempts to resolve the reference to a non-reference value. */
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700222 Value* ResolveReference(Reference* ref, const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700223 const int kMaxIterations = 40;
224 int i = 0;
225 while (ref && ref->id && i++ < kMaxIterations) {
226 auto table = extractor_->apk_->GetResourceTable();
227 if (auto value = FindValueById(table, ref->id.value(), config)) {
228 if (ValueCast<Reference>(value)) {
229 ref = ValueCast<Reference>(value);
230 } else {
231 return value;
232 }
233 }
234 }
235 return nullptr;
236 }
237
238 /**
239 * Retrieves the integer value of the attribute . If the value of the attribute is a reference,
240 * this will attempt to resolve the reference to an integer value.
241 **/
242 int32_t* GetAttributeInteger(xml::Attribute* attr,
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700243 const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700244 if (attr != nullptr) {
245 if (attr->compiled_value) {
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700246 // Resolve references using the configuration
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700247 Value* value = attr->compiled_value.get();
248 if (ValueCast<Reference>(value)) {
249 value = ResolveReference(ValueCast<Reference>(value), config);
250 } else {
251 value = attr->compiled_value.get();
252 }
253 // Retrieve the integer data if possible
254 if (value != nullptr) {
255 if (BinaryPrimitive* intValue = ValueCast<BinaryPrimitive>(value)) {
256 return (int32_t*) &intValue->value.data;
257 }
258 }
259 }
260 }
261 return nullptr;
262 }
263
264 /**
265 * A version of GetAttributeInteger that returns a default integer if the attribute does not
266 * exist or cannot be resolved to an integer value.
267 **/
268 int32_t GetAttributeIntegerDefault(xml::Attribute* attr, int32_t def,
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700269 const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700270 auto value = GetAttributeInteger(attr, config);
271 if (value) {
272 return *value;
273 }
274 return def;
275 }
276
277 /**
278 * Retrieves the string value of the attribute. If the value of the attribute is a reference,
279 * this will attempt to resolve the reference to a string value.
280 **/
281 const std::string* GetAttributeString(xml::Attribute* attr,
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700282 const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700283 if (attr != nullptr) {
284 if (attr->compiled_value) {
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700285 // Resolve references using the configuration
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700286 Value* value = attr->compiled_value.get();
287 if (ValueCast<Reference>(value)) {
288 value = ResolveReference(ValueCast<Reference>(value), config);
289 } else {
290 value = attr->compiled_value.get();
291 }
292
293 // Retrieve the string data of the value if possible
294 if (value != nullptr) {
295 if (String* intValue = ValueCast<String>(value)) {
296 return &(*intValue->value);
297 } else if (RawString* rawValue = ValueCast<RawString>(value)) {
298 return &(*rawValue->value);
299 } else if (FileReference* strValue = ValueCast<FileReference>(value)) {
300 return &(*strValue->path);
301 }
302 }
303 }
Ryan Mitchella36cc982019-06-05 10:13:41 -0700304
305 if (!attr->value.empty()) {
306 return &attr->value;
307 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700308 }
309 return nullptr;
310 }
311
312 /**
313 * A version of GetAttributeString that returns a default string if the attribute does not
314 * exist or cannot be resolved to an string value.
315 **/
316 std::string GetAttributeStringDefault(xml::Attribute* attr, std::string def,
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700317 const ConfigDescription& config = DefaultConfig()) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700318 auto value = GetAttributeString(attr, config);
319 if (value) {
320 return *value;
321 }
322 return def;
323 }
324
325 private:
326 ManifestExtractor* extractor_;
327 std::vector<std::unique_ptr<Element>> children_;
328 std::string tag_;
329 };
330
331 friend Element;
332
333 /** Creates a default configuration used to retrieve resources. */
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700334 static ConfigDescription DefaultConfig() {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700335 ConfigDescription config;
336 config.orientation = android::ResTable_config::ORIENTATION_PORT;
337 config.density = android::ResTable_config::DENSITY_MEDIUM;
Jackal Guo201a60a2021-08-31 12:37:30 +0800338 config.sdkVersion = SDK_CUR_DEVELOPMENT; // Very high.
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700339 config.screenWidthDp = 320;
340 config.screenHeightDp = 480;
341 config.smallestScreenWidthDp = 320;
342 config.screenLayout |= android::ResTable_config::SCREENSIZE_NORMAL;
343 return config;
344 }
345
Iurii Makhnoa9c74c52022-04-12 15:04:12 +0000346 bool Extract(IDiagnostics* diag);
347 bool Dump(text::Printer* printer);
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700348
349 /** Recursively visit the xml element tree and return a processed badging element tree. */
350 std::unique_ptr<Element> Visit(xml::Element* element);
351
352 /** Raises the target sdk value if the min target is greater than the current target. */
353 void RaiseTargetSdk(int32_t min_target) {
354 if (min_target > target_sdk_) {
355 target_sdk_ = min_target;
356 }
357 }
358
359 /**
360 * Retrieves the default feature group that features are added into when <uses-feature>
361 * are not in a <feature-group> element.
362 **/
Iurii Makhnoa9c74c52022-04-12 15:04:12 +0000363 CommonFeatureGroup* common_feature_group() {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700364 return commonFeatureGroup_.get();
365 }
366
367 /**
368 * Retrieves a mapping of density values to Configurations for retrieving resources that would be
369 * used for that density setting.
370 **/
371 const std::map<uint16_t, ConfigDescription> densities() const {
372 return densities_;
373 }
374
375 /**
376 * Retrieves a mapping of locale BCP 47 strings to Configurations for retrieving resources that
377 * would be used for that locale setting.
378 **/
379 const std::map<std::string, ConfigDescription> locales() const {
380 return locales_;
381 }
382
383 /** Retrieves the current stack of parent during data extraction. */
384 const std::vector<Element*> parent_stack() const {
385 return parent_stack_;
386 }
387
388 int32_t target_sdk() const {
389 return target_sdk_;
390 }
391
392 LoadedApk* const apk_;
Ryan Mitchell214846d2018-09-19 16:57:01 -0700393 DumpManifestOptions& options_;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700394
395 private:
Iurii Makhnoa9c74c52022-04-12 15:04:12 +0000396 std::unique_ptr<xml::XmlResource> doc_;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700397 std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
398 std::map<std::string, ConfigDescription> locales_;
399 std::map<uint16_t, ConfigDescription> densities_;
400 std::vector<Element*> parent_stack_;
401 int32_t target_sdk_ = 0;
Iurii Makhnoa9c74c52022-04-12 15:04:12 +0000402
403 std::unique_ptr<ManifestExtractor::Element> root_element_;
404 std::vector<std::unique_ptr<ManifestExtractor::Element>> implied_permissions_;
405 std::set<std::string> components_;
406 std::vector<FeatureGroup*> feature_groups_;
407 bool other_activities_ = false;
408 bool other_receivers_ = false;
409 bool other_services_ = false;
410 std::unique_ptr<Architectures> architectures_ = util::make_unique<Architectures>();
411 const SupportsScreen* supports_screen_;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700412};
413
414template<typename T> T* ElementCast(ManifestExtractor::Element* element);
415
416/** Recurs through the children of the specified root in depth-first order. */
417static void ForEachChild(ManifestExtractor::Element* root,
418 std::function<void(ManifestExtractor::Element*)> f) {
419 for (auto& child : root->children()) {
420 f(child.get());
421 ForEachChild(child.get(), f);
422 }
423}
424
425/**
426 * Checks the element and its recursive children for an element that makes the specified
427 * conditional function return true. Returns the first element that makes the conditional function
428 * return true.
429 **/
430static ManifestExtractor::Element* FindElement(ManifestExtractor::Element* root,
431 std::function<bool(ManifestExtractor::Element*)> f) {
432 if (f(root)) {
433 return root;
434 }
435 for (auto& child : root->children()) {
436 if (auto b2 = FindElement(child.get(), f)) {
437 return b2;
438 }
439 }
440 return nullptr;
441}
442
443/** Represents the <manifest> elements **/
444class Manifest : public ManifestExtractor::Element {
445 public:
446 Manifest() = default;
Iurii Makhnoa9c74c52022-04-12 15:04:12 +0000447 bool only_package_name;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700448 std::string package;
449 int32_t versionCode;
450 std::string versionName;
451 const std::string* split = nullptr;
452 const std::string* platformVersionName = nullptr;
453 const std::string* platformVersionCode = nullptr;
Ryan Mitchella36cc982019-06-05 10:13:41 -0700454 const int32_t* platformVersionNameInt = nullptr;
455 const int32_t* platformVersionCodeInt = nullptr;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700456 const int32_t* compilesdkVersion = nullptr;
457 const std::string* compilesdkVersionCodename = nullptr;
458 const int32_t* installLocation = nullptr;
459
460 void Extract(xml::Element* manifest) override {
461 package = GetAttributeStringDefault(FindAttribute(manifest, {}, "package"), "");
462 versionCode = GetAttributeIntegerDefault(FindAttribute(manifest, VERSION_CODE_ATTR), 0);
463 versionName = GetAttributeStringDefault(FindAttribute(manifest, VERSION_NAME_ATTR), "");
464 split = GetAttributeString(FindAttribute(manifest, {}, "split"));
465
466 // Extract the platform build info
467 platformVersionName = GetAttributeString(FindAttribute(manifest, {},
468 "platformBuildVersionName"));
469 platformVersionCode = GetAttributeString(FindAttribute(manifest, {},
470 "platformBuildVersionCode"));
Ryan Mitchella36cc982019-06-05 10:13:41 -0700471 platformVersionNameInt = GetAttributeInteger(FindAttribute(manifest, {},
472 "platformBuildVersionName"));
473 platformVersionCodeInt = GetAttributeInteger(FindAttribute(manifest, {},
474 "platformBuildVersionCode"));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700475
476 // Extract the compile sdk info
477 compilesdkVersion = GetAttributeInteger(FindAttribute(manifest, COMPILE_SDK_VERSION_ATTR));
478 compilesdkVersionCodename = GetAttributeString(
479 FindAttribute(manifest, COMPILE_SDK_VERSION_CODENAME_ATTR));
480 installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR));
481 }
482
Ryan Mitchell214846d2018-09-19 16:57:01 -0700483 void Print(text::Printer* printer) override {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +0000484 if (only_package_name) {
485 printer->Println(StringPrintf("package: %s", package.data()));
486 } else {
487 PrintFull(printer);
488 }
489 }
490
491 void PrintFull(text::Printer* printer) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700492 printer->Print(StringPrintf("package: name='%s' ", package.data()));
493 printer->Print(StringPrintf("versionCode='%s' ",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700494 (versionCode > 0) ? std::to_string(versionCode).data() : ""));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700495 printer->Print(StringPrintf("versionName='%s'", versionName.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700496
497 if (split) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700498 printer->Print(StringPrintf(" split='%s'", split->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700499 }
500 if (platformVersionName) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700501 printer->Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
Dave Ingram7e0e4c12019-08-01 15:11:41 -0700502 } else if (platformVersionNameInt) {
Ryan Mitchella36cc982019-06-05 10:13:41 -0700503 printer->Print(StringPrintf(" platformBuildVersionName='%d'", *platformVersionNameInt));
504 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700505 if (platformVersionCode) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700506 printer->Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
Dave Ingram7e0e4c12019-08-01 15:11:41 -0700507 } else if (platformVersionCodeInt) {
Ryan Mitchella36cc982019-06-05 10:13:41 -0700508 printer->Print(StringPrintf(" platformBuildVersionCode='%d'", *platformVersionCodeInt));
509 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700510 if (compilesdkVersion) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700511 printer->Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700512 }
513 if (compilesdkVersionCodename) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700514 printer->Print(StringPrintf(" compileSdkVersionCodename='%s'",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700515 compilesdkVersionCodename->data()));
516 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700517 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700518
519 if (installLocation) {
520 switch (*installLocation) {
521 case 0:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700522 printer->Print("install-location:'auto'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700523 break;
524 case 1:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700525 printer->Print("install-location:'internalOnly'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700526 break;
527 case 2:
Ryan Mitchell214846d2018-09-19 16:57:01 -0700528 printer->Print("install-location:'preferExternal'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700529 break;
530 default:
531 break;
532 }
533 }
534 }
535};
536
537/** Represents <application> elements. **/
538class Application : public ManifestExtractor::Element {
539 public:
540 Application() = default;
541 std::string label;
542 std::string icon;
543 std::string banner;
544 int32_t is_game;
545 int32_t debuggable;
546 int32_t test_only;
547 bool has_multi_arch;
548
549 /** Mapping from locales to app names. */
550 std::map<std::string, std::string> locale_labels;
551
552 /** Mapping from densities to app icons. */
553 std::map<uint16_t, std::string> density_icons;
554
555 void Extract(xml::Element* element) override {
556 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
557 icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
558 test_only = GetAttributeIntegerDefault(FindAttribute(element, TEST_ONLY_ATTR), 0);
559 banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
560 is_game = GetAttributeIntegerDefault(FindAttribute(element, ISGAME_ATTR), 0);
561 debuggable = GetAttributeIntegerDefault(FindAttribute(element, DEBUGGABLE_ATTR), 0);
562
563 // We must search by name because the multiArch flag hasn't been API
564 // frozen yet.
565 has_multi_arch = (GetAttributeIntegerDefault(
566 FindAttribute(element, kAndroidNamespace, "multiArch"), 0) != 0);
567
568 // Retrieve the app names for every locale the app supports
569 auto attr = FindAttribute(element, LABEL_ATTR);
570 for (auto& config : extractor()->locales()) {
571 if (auto label = GetAttributeString(attr, config.second)) {
572 if (label) {
573 locale_labels.insert(std::make_pair(config.first, *label));
574 }
575 }
576 }
577
578 // Retrieve the icons for the densities the app supports
579 attr = FindAttribute(element, ICON_ATTR);
580 for (auto& config : extractor()->densities()) {
581 if (auto resource = GetAttributeString(attr, config.second)) {
582 if (resource) {
583 density_icons.insert(std::make_pair(config.first, *resource));
584 }
585 }
586 }
587 }
588
Ryan Mitchell214846d2018-09-19 16:57:01 -0700589 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700590 // Print the labels for every locale
591 for (auto p : locale_labels) {
592 if (p.first.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700593 printer->Print(StringPrintf("application-label:'%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700594 android::ResTable::normalizeForOutput(p.second.data())
595 .c_str()));
596 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700597 printer->Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(),
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700598 android::ResTable::normalizeForOutput(p.second.data())
599 .c_str()));
600 }
601 }
602
603 // Print the icon paths for every density
604 for (auto p : density_icons) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700605 printer->Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700606 }
607
608 // Print the application info
Ryan Mitchell214846d2018-09-19 16:57:01 -0700609 printer->Print(StringPrintf("application: label='%s' ",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700610 android::ResTable::normalizeForOutput(label.data()).c_str()));
Ryan Mitchell214846d2018-09-19 16:57:01 -0700611 printer->Print(StringPrintf("icon='%s'", icon.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700612 if (!banner.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700613 printer->Print(StringPrintf(" banner='%s'", banner.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700614 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700615 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700616
617 if (test_only != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700618 printer->Print(StringPrintf("testOnly='%d'\n", test_only));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700619 }
620 if (is_game != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700621 printer->Print("application-isGame\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700622 }
623 if (debuggable != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700624 printer->Print("application-debuggable\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700625 }
626 }
627};
628
629/** Represents <uses-sdk> elements. **/
630class UsesSdkBadging : public ManifestExtractor::Element {
631 public:
632 UsesSdkBadging() = default;
633 const int32_t* min_sdk = nullptr;
634 const std::string* min_sdk_name = nullptr;
635 const int32_t* max_sdk = nullptr;
636 const int32_t* target_sdk = nullptr;
637 const std::string* target_sdk_name = nullptr;
638
639 void Extract(xml::Element* element) override {
640 min_sdk = GetAttributeInteger(FindAttribute(element, MIN_SDK_VERSION_ATTR));
641 min_sdk_name = GetAttributeString(FindAttribute(element, MIN_SDK_VERSION_ATTR));
642 max_sdk = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
643 target_sdk = GetAttributeInteger(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
644 target_sdk_name = GetAttributeString(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
645
646 // Detect the target sdk of the element
647 if ((min_sdk_name && *min_sdk_name == "Donut")
648 || (target_sdk_name && *target_sdk_name == "Donut")) {
Jackal Guo201a60a2021-08-31 12:37:30 +0800649 extractor()->RaiseTargetSdk(SDK_DONUT);
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700650 }
651 if (min_sdk) {
652 extractor()->RaiseTargetSdk(*min_sdk);
653 }
654 if (target_sdk) {
655 extractor()->RaiseTargetSdk(*target_sdk);
Ryan Mitchell95f02422020-04-30 10:25:53 -0700656 } else if (target_sdk_name) {
Jackal Guo201a60a2021-08-31 12:37:30 +0800657 extractor()->RaiseTargetSdk(SDK_CUR_DEVELOPMENT);
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700658 }
659 }
660
Ryan Mitchell214846d2018-09-19 16:57:01 -0700661 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700662 if (min_sdk) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700663 printer->Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700664 } else if (min_sdk_name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700665 printer->Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700666 }
667 if (max_sdk) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700668 printer->Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700669 }
670 if (target_sdk) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700671 printer->Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700672 } else if (target_sdk_name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700673 printer->Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700674 }
675 }
676};
677
678/** Represents <uses-configuration> elements. **/
679class UsesConfiguarion : public ManifestExtractor::Element {
680 public:
681 UsesConfiguarion() = default;
682 int32_t req_touch_screen = 0;
683 int32_t req_keyboard_type = 0;
684 int32_t req_hard_keyboard = 0;
685 int32_t req_navigation = 0;
686 int32_t req_five_way_nav = 0;
687
688 void Extract(xml::Element* element) override {
689 req_touch_screen = GetAttributeIntegerDefault(
690 FindAttribute(element, REQ_TOUCH_SCREEN_ATTR), 0);
691 req_keyboard_type = GetAttributeIntegerDefault(
692 FindAttribute(element, REQ_KEYBOARD_TYPE_ATTR), 0);
693 req_hard_keyboard = GetAttributeIntegerDefault(
694 FindAttribute(element, REQ_HARD_KEYBOARD_ATTR), 0);
695 req_navigation = GetAttributeIntegerDefault(
696 FindAttribute(element, REQ_NAVIGATION_ATTR), 0);
697 req_five_way_nav = GetAttributeIntegerDefault(
698 FindAttribute(element, REQ_FIVE_WAY_NAV_ATTR), 0);
699 }
700
Ryan Mitchell214846d2018-09-19 16:57:01 -0700701 void Print(text::Printer* printer) override {
702 printer->Print("uses-configuration:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700703 if (req_touch_screen != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700704 printer->Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700705 }
706 if (req_keyboard_type != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700707 printer->Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700708 }
709 if (req_hard_keyboard != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700710 printer->Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700711 }
712 if (req_navigation != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700713 printer->Print(StringPrintf(" reqNavigation='%d'", req_navigation));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700714 }
715 if (req_five_way_nav != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700716 printer->Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700717 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700718 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700719 }
720};
721
722/** Represents <supports-screen> elements. **/
723class SupportsScreen : public ManifestExtractor::Element {
724 public:
725 SupportsScreen() = default;
726 int32_t small_screen = 1;
727 int32_t normal_screen = 1;
728 int32_t large_screen = 1;
729 int32_t xlarge_screen = 1;
730 int32_t any_density = 1;
731 int32_t requires_smallest_width_dp = 0;
732 int32_t compatible_width_limit_dp = 0;
733 int32_t largest_width_limit_dp = 0;
734
735 void Extract(xml::Element* element) override {
736 small_screen = GetAttributeIntegerDefault(FindAttribute(element, SMALL_SCREEN_ATTR), 1);
737 normal_screen = GetAttributeIntegerDefault(FindAttribute(element, NORMAL_SCREEN_ATTR), 1);
738 large_screen = GetAttributeIntegerDefault(FindAttribute(element, LARGE_SCREEN_ATTR), 1);
739 xlarge_screen = GetAttributeIntegerDefault(FindAttribute(element, XLARGE_SCREEN_ATTR), 1);
740 any_density = GetAttributeIntegerDefault(FindAttribute(element, ANY_DENSITY_ATTR), 1);
741
742 requires_smallest_width_dp = GetAttributeIntegerDefault(
743 FindAttribute(element, REQUIRES_SMALLEST_WIDTH_DP_ATTR), 0);
744 compatible_width_limit_dp = GetAttributeIntegerDefault(
745 FindAttribute(element, COMPATIBLE_WIDTH_LIMIT_DP_ATTR), 0);
746 largest_width_limit_dp = GetAttributeIntegerDefault(
747 FindAttribute(element, LARGEST_WIDTH_LIMIT_DP_ATTR), 0);
748
749 // For modern apps, if screen size buckets haven't been specified
750 // but the new width ranges have, then infer the buckets from them.
751 if (small_screen > 0 && normal_screen > 0 && large_screen > 0 && xlarge_screen > 0
752 && requires_smallest_width_dp > 0) {
753 int32_t compat_width = (compatible_width_limit_dp > 0) ? compatible_width_limit_dp
754 : requires_smallest_width_dp;
755 small_screen = (requires_smallest_width_dp <= 240 && compat_width >= 240) ? -1 : 0;
756 normal_screen = (requires_smallest_width_dp <= 320 && compat_width >= 320) ? -1 : 0;
757 large_screen = (requires_smallest_width_dp <= 480 && compat_width >= 480) ? -1 : 0;
758 xlarge_screen = (requires_smallest_width_dp <= 720 && compat_width >= 720) ? -1 : 0;
759 }
760 }
761
Iurii Makhnoa9c74c52022-04-12 15:04:12 +0000762 void PrintScreens(text::Printer* printer, int32_t target_sdk) const {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700763 int32_t small_screen_temp = small_screen;
764 int32_t normal_screen_temp = normal_screen;
765 int32_t large_screen_temp = large_screen;
766 int32_t xlarge_screen_temp = xlarge_screen;
767 int32_t any_density_temp = any_density;
768
769 // Determine default values for any unspecified screen sizes,
770 // based on the target SDK of the package. As of 4 (donut)
771 // the screen size support was introduced, so all default to
772 // enabled.
773 if (small_screen_temp > 0) {
Jackal Guo201a60a2021-08-31 12:37:30 +0800774 small_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700775 }
776 if (normal_screen_temp > 0) {
777 normal_screen_temp = -1;
778 }
779 if (large_screen_temp > 0) {
Jackal Guo201a60a2021-08-31 12:37:30 +0800780 large_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700781 }
782 if (xlarge_screen_temp > 0) {
783 // Introduced in Gingerbread.
Jackal Guo201a60a2021-08-31 12:37:30 +0800784 xlarge_screen_temp = target_sdk >= SDK_GINGERBREAD ? -1 : 0;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700785 }
786 if (any_density_temp > 0) {
Jackal Guo201a60a2021-08-31 12:37:30 +0800787 any_density_temp = (target_sdk >= SDK_DONUT || requires_smallest_width_dp > 0 ||
788 compatible_width_limit_dp > 0)
789 ? -1
790 : 0;
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700791 }
792
793 // Print the formatted screen info
Ryan Mitchell214846d2018-09-19 16:57:01 -0700794 printer->Print("supports-screens:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700795 if (small_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700796 printer->Print(" 'small'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700797 }
798 if (normal_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700799 printer->Print(" 'normal'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700800 }
801 if (large_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700802 printer->Print(" 'large'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700803 }
804 if (xlarge_screen_temp != 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700805 printer->Print(" 'xlarge'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700806 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700807 printer->Print("\n");
808 printer->Print(StringPrintf("supports-any-density: '%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700809 (any_density_temp ) ? "true" : "false"));
810 if (requires_smallest_width_dp > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700811 printer->Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700812 }
813 if (compatible_width_limit_dp > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700814 printer->Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700815 }
816 if (largest_width_limit_dp > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700817 printer->Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700818 }
819 }
820};
821
822/** Represents <feature-group> elements. **/
823class FeatureGroup : public ManifestExtractor::Element {
824 public:
825 FeatureGroup() = default;
826 std::string label;
827 int32_t open_gles_version = 0;
828
829 void Extract(xml::Element* element) override {
830 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
831 }
832
Ryan Mitchell214846d2018-09-19 16:57:01 -0700833 virtual void PrintGroup(text::Printer* printer) {
834 printer->Print(StringPrintf("feature-group: label='%s'\n", label.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700835 if (open_gles_version > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700836 printer->Print(StringPrintf(" uses-gl-es: '0x%x'\n", open_gles_version));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700837 }
838
839 for (auto feature : features_) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700840 printer->Print(StringPrintf(" uses-feature%s: name='%s'",
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700841 (feature.second.required ? "" : "-not-required"),
842 feature.first.data()));
843 if (feature.second.version > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700844 printer->Print(StringPrintf(" version='%d'", feature.second.version));
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700845 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700846 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700847 }
848 }
849
850 /** Adds a feature to the feature group. */
851 void AddFeature(const std::string& name, bool required = true, int32_t version = -1) {
852 features_.insert(std::make_pair(name, Feature{ required, version }));
853 if (required) {
854 if (name == "android.hardware.camera.autofocus" ||
855 name == "android.hardware.camera.flash") {
856 AddFeature("android.hardware.camera", true);
857 } else if (name == "android.hardware.location.gps" ||
858 name == "android.hardware.location.network") {
859 AddFeature("android.hardware.location", true);
860 } else if (name == "android.hardware.faketouch.multitouch") {
861 AddFeature("android.hardware.faketouch", true);
862 } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
863 name == "android.hardware.faketouch.multitouch.jazzhands") {
864 AddFeature("android.hardware.faketouch.multitouch", true);
865 AddFeature("android.hardware.faketouch", true);
866 } else if (name == "android.hardware.touchscreen.multitouch") {
867 AddFeature("android.hardware.touchscreen", true);
868 } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
869 name == "android.hardware.touchscreen.multitouch.jazzhands") {
870 AddFeature("android.hardware.touchscreen.multitouch", true);
871 AddFeature("android.hardware.touchscreen", true);
872 } else if (name == "android.hardware.opengles.aep") {
873 const int kOpenGLESVersion31 = 0x00030001;
874 if (kOpenGLESVersion31 > open_gles_version) {
875 open_gles_version = kOpenGLESVersion31;
876 }
877 }
878 }
879 }
880
881 /** Returns true if the feature group has the given feature. */
882 virtual bool HasFeature(const std::string& name) {
883 return features_.find(name) != features_.end();
884 }
885
886 /** Merges the features of another feature group into this group. */
887 void Merge(FeatureGroup* group) {
888 open_gles_version = std::max(open_gles_version, group->open_gles_version);
889 for (auto& feature : group->features_) {
890 features_.insert(feature);
891 }
892 }
893
894 protected:
895 struct Feature {
896 public:
897 bool required = false;
898 int32_t version = -1;
899 };
900
901 /* Mapping of feature names to their properties. */
902 std::map<std::string, Feature> features_;
903};
904
905/**
906 * Represents the default feature group for the application if no <feature-group> elements are
907 * present in the manifest.
908 **/
909class CommonFeatureGroup : public FeatureGroup {
910 public:
911 CommonFeatureGroup() = default;
Ryan Mitchell214846d2018-09-19 16:57:01 -0700912 void PrintGroup(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700913 FeatureGroup::PrintGroup(printer);
914
915 // Also print the implied features
916 for (auto feature : implied_features_) {
917 if (features_.find(feature.first) == features_.end()) {
918 const char* sdk23 = feature.second.implied_from_sdk_k23 ? "-sdk-23" : "";
Ryan Mitchell214846d2018-09-19 16:57:01 -0700919 printer->Print(StringPrintf(" uses-feature%s: name='%s'\n", sdk23, feature.first.data()));
920 printer->Print(StringPrintf(" uses-implied-feature%s: name='%s' reason='", sdk23,
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700921 feature.first.data()));
922
923 // Print the reasons as a sentence
924 size_t count = 0;
925 for (auto reason : feature.second.reasons) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700926 printer->Print(reason);
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700927 if (count + 2 < feature.second.reasons.size()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700928 printer->Print(", ");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700929 } else if (count + 1 < feature.second.reasons.size()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -0700930 printer->Print(", and ");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700931 }
932 count++;
933 }
Ryan Mitchell214846d2018-09-19 16:57:01 -0700934 printer->Print("'\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -0700935 }
936 }
937 }
938
939 /** Returns true if the feature group has the given feature. */
940 bool HasFeature(const std::string& name) override {
941 return FeatureGroup::HasFeature(name)
942 || implied_features_.find(name) != implied_features_.end();
943 }
944
945 /** Adds a feature to a set of implied features not explicitly requested in the manifest. */
946 void addImpliedFeature(const std::string& name, const std::string& reason, bool sdk23 = false) {
947 auto entry = implied_features_.find(name);
948 if (entry == implied_features_.end()) {
949 implied_features_.insert(std::make_pair(name, ImpliedFeature(sdk23)));
950 entry = implied_features_.find(name);
951 }
952
953 // A non-sdk 23 implied feature takes precedence.
954 if (entry->second.implied_from_sdk_k23 && !sdk23) {
955 entry->second.implied_from_sdk_k23 = false;
956 }
957
958 entry->second.reasons.insert(reason);
959 }
960
961 /**
962 * Adds a feature to a set of implied features for all features that are implied by the presence
963 * of the permission.
964 **/
965 void addImpliedFeaturesForPermission(int32_t targetSdk, const std::string& name, bool sdk23) {
966 if (name == "android.permission.CAMERA") {
967 addImpliedFeature("android.hardware.camera",
968 StringPrintf("requested %s permission", name.data()),
969 sdk23);
970
971 } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
972 if (targetSdk < SDK_LOLLIPOP) {
973 addImpliedFeature("android.hardware.location.gps",
974 StringPrintf("requested %s permission", name.data()),
975 sdk23);
976 addImpliedFeature("android.hardware.location.gps",
977 StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
978 sdk23);
979 }
980 addImpliedFeature("android.hardware.location",
981 StringPrintf("requested %s permission", name.data()),
982 sdk23);
983
984 } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
985 if (targetSdk < SDK_LOLLIPOP) {
986 addImpliedFeature("android.hardware.location.network",
987 StringPrintf("requested %s permission", name.data()),
988 sdk23);
989 addImpliedFeature("android.hardware.location.network",
990 StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
991 sdk23);
992 }
993 addImpliedFeature("android.hardware.location",
994 StringPrintf("requested %s permission", name.data()),
995 sdk23);
996
997 } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
998 name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
999 name == "android.permission.INSTALL_LOCATION_PROVIDER") {
1000 addImpliedFeature("android.hardware.location",
1001 StringPrintf("requested %s permission", name.data()),
1002 sdk23);
1003
1004 } else if (name == "android.permission.BLUETOOTH" ||
1005 name == "android.permission.BLUETOOTH_ADMIN") {
1006 if (targetSdk > SDK_DONUT) {
1007 addImpliedFeature("android.hardware.bluetooth",
1008 StringPrintf("requested %s permission", name.data()),
1009 sdk23);
1010 addImpliedFeature("android.hardware.bluetooth",
1011 StringPrintf("targetSdkVersion > %d", SDK_DONUT),
1012 sdk23);
1013 }
1014
1015 } else if (name == "android.permission.RECORD_AUDIO") {
1016 addImpliedFeature("android.hardware.microphone",
1017 StringPrintf("requested %s permission", name.data()),
1018 sdk23);
1019
1020 } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
1021 name == "android.permission.CHANGE_WIFI_STATE" ||
1022 name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
1023 addImpliedFeature("android.hardware.wifi",
1024 StringPrintf("requested %s permission", name.data()),
1025 sdk23);
1026
1027 } else if (name == "android.permission.CALL_PHONE" ||
1028 name == "android.permission.CALL_PRIVILEGED" ||
1029 name == "android.permission.MODIFY_PHONE_STATE" ||
1030 name == "android.permission.PROCESS_OUTGOING_CALLS" ||
1031 name == "android.permission.READ_SMS" ||
1032 name == "android.permission.RECEIVE_SMS" ||
1033 name == "android.permission.RECEIVE_MMS" ||
1034 name == "android.permission.RECEIVE_WAP_PUSH" ||
1035 name == "android.permission.SEND_SMS" ||
1036 name == "android.permission.WRITE_APN_SETTINGS" ||
1037 name == "android.permission.WRITE_SMS") {
1038 addImpliedFeature("android.hardware.telephony",
1039 "requested a telephony permission",
1040 sdk23);
1041 }
1042 }
1043
1044 private:
1045 /**
1046 * Represents a feature that has been automatically added due to a pre-requisite or for some
1047 * other reason.
1048 */
1049 struct ImpliedFeature {
1050 explicit ImpliedFeature(bool sdk23 = false) : implied_from_sdk_k23(sdk23) {}
1051
1052 /** List of human-readable reasons for why this feature was implied. */
1053 std::set<std::string> reasons;
1054
1055 // Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)
1056 bool implied_from_sdk_k23;
1057 };
1058
1059 /* Mapping of implied feature names to their properties. */
1060 std::map<std::string, ImpliedFeature> implied_features_;
1061};
1062
1063/** Represents <uses-feature> elements. **/
1064class UsesFeature : public ManifestExtractor::Element {
1065 public:
1066 UsesFeature() = default;
1067 void Extract(xml::Element* element) override {
1068 const std::string* name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1069 int32_t* gl = GetAttributeInteger(FindAttribute(element, GL_ES_VERSION_ATTR));
1070 bool required = GetAttributeIntegerDefault(
1071 FindAttribute(element, REQUIRED_ATTR), true) != 0;
1072 int32_t version = GetAttributeIntegerDefault(
1073 FindAttribute(element, kAndroidNamespace, "version"), 0);
1074
1075 // Add the feature to the parent feature group element if one exists; otherwise, add it to the
1076 // common feature group
1077 FeatureGroup* feature_group = ElementCast<FeatureGroup>(extractor()->parent_stack()[0]);
1078 if (!feature_group) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00001079 feature_group = extractor()->common_feature_group();
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001080 } else {
1081 // All features in side of <feature-group> elements are required.
1082 required = true;
1083 }
1084
1085 if (name) {
1086 feature_group->AddFeature(*name, required, version);
1087 } else if (gl) {
1088 feature_group->open_gles_version = std::max(feature_group->open_gles_version, *gl);
1089 }
1090 }
1091};
1092
1093/** Represents <uses-permission> elements. **/
1094class UsesPermission : public ManifestExtractor::Element {
1095 public:
1096 UsesPermission() = default;
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00001097 bool implied;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001098 std::string name;
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00001099 std::vector<std::string> requiredFeatures;
1100 std::vector<std::string> requiredNotFeatures;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001101 int32_t required = true;
1102 int32_t maxSdkVersion = -1;
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -06001103 int32_t usesPermissionFlags = 0;
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00001104 std::string impliedReason;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001105
1106 void Extract(xml::Element* element) override {
1107 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00001108 std::string feature =
1109 GetAttributeStringDefault(FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
1110 if (!feature.empty()) {
1111 requiredFeatures.push_back(feature);
1112 }
1113 feature = GetAttributeStringDefault(FindAttribute(element, REQUIRED_NOT_FEATURE_ATTR), "");
1114 if (!feature.empty()) {
1115 requiredNotFeatures.push_back(feature);
1116 }
1117
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001118 required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
1119 maxSdkVersion = GetAttributeIntegerDefault(
1120 FindAttribute(element, MAX_SDK_VERSION_ATTR), -1);
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -06001121 usesPermissionFlags = GetAttributeIntegerDefault(
1122 FindAttribute(element, USES_PERMISSION_FLAGS_ATTR), 0);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001123
1124 if (!name.empty()) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00001125 CommonFeatureGroup* common = extractor()->common_feature_group();
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001126 common->addImpliedFeaturesForPermission(extractor()->target_sdk(), name, false);
1127 }
1128 }
1129
Ryan Mitchell214846d2018-09-19 16:57:01 -07001130 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001131 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001132 printer->Print(StringPrintf("uses-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("\n");
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00001140 for (const std::string& requiredFeature : requiredFeatures) {
1141 printer->Print(StringPrintf(" required-feature='%s'\n", requiredFeature.data()));
1142 }
1143 for (const std::string& requiredNotFeature : requiredNotFeatures) {
1144 printer->Print(StringPrintf(" required-not-feature='%s'\n", requiredNotFeature.data()));
1145 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001146 if (required == 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001147 printer->Print(StringPrintf("optional-permission: name='%s'", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001148 if (maxSdkVersion >= 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001149 printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001150 }
Jeff Sharkeyabcddfd2021-03-29 10:05:21 -06001151 if ((usesPermissionFlags & kNeverForLocation) != 0) {
1152 printer->Print(StringPrintf(" usesPermissionFlags='neverForLocation'"));
1153 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001154 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001155 }
1156 }
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00001157 if (implied) {
1158 printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
1159 if (maxSdkVersion >= 0) {
1160 printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
1161 }
1162 if ((usesPermissionFlags & kNeverForLocation) != 0) {
1163 printer->Print(StringPrintf(" usesPermissionFlags='neverForLocation'"));
1164 }
1165 printer->Print(StringPrintf(" reason='%s'\n", impliedReason.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001166 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001167 }
1168};
1169
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00001170/** Represents <required-feature> elements. **/
1171class RequiredFeature : public ManifestExtractor::Element {
1172 public:
1173 RequiredFeature() = default;
1174 std::string name;
1175
1176 void Extract(xml::Element* element) override {
1177 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1178 auto parent_stack = extractor()->parent_stack();
1179 if (!name.empty() && ElementCast<UsesPermission>(parent_stack[0])) {
1180 UsesPermission* uses_permission = ElementCast<UsesPermission>(parent_stack[0]);
1181 uses_permission->requiredFeatures.push_back(name);
1182 }
1183 }
1184};
1185
1186/** Represents <required-not-feature> elements. **/
1187class RequiredNotFeature : public ManifestExtractor::Element {
1188 public:
1189 RequiredNotFeature() = default;
1190 std::string name;
1191
1192 void Extract(xml::Element* element) override {
1193 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1194 auto parent_stack = extractor()->parent_stack();
1195 if (!name.empty() && ElementCast<UsesPermission>(parent_stack[0])) {
1196 UsesPermission* uses_permission = ElementCast<UsesPermission>(parent_stack[0]);
1197 uses_permission->requiredNotFeatures.push_back(name);
1198 }
1199 }
1200};
1201
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001202/** Represents <uses-permission-sdk-23> elements. **/
1203class UsesPermissionSdk23 : public ManifestExtractor::Element {
1204 public:
1205 UsesPermissionSdk23() = default;
1206 const std::string* name = nullptr;
1207 const int32_t* maxSdkVersion = nullptr;
1208
1209 void Extract(xml::Element* element) override {
1210 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1211 maxSdkVersion = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
1212
1213 if (name) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00001214 CommonFeatureGroup* common = extractor()->common_feature_group();
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001215 common->addImpliedFeaturesForPermission(extractor()->target_sdk(), *name, true);
1216 }
1217 }
1218
Ryan Mitchell214846d2018-09-19 16:57:01 -07001219 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001220 if (name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001221 printer->Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001222 if (maxSdkVersion) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001223 printer->Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001224 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001225 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001226 }
1227 }
1228};
1229
1230/** Represents <permission> elements. These elements are only printing when dumping permissions. **/
1231class Permission : public ManifestExtractor::Element {
1232 public:
1233 Permission() = default;
1234 std::string name;
1235
1236 void Extract(xml::Element* element) override {
1237 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1238 }
1239
Ryan Mitchell214846d2018-09-19 16:57:01 -07001240 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001241 if (extractor()->options_.only_permissions && !name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001242 printer->Print(StringPrintf("permission: %s\n", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001243 }
1244 }
1245};
1246
1247/** Represents <activity> elements. **/
1248class Activity : public ManifestExtractor::Element {
1249 public:
1250 Activity() = default;
1251 std::string name;
1252 std::string icon;
1253 std::string label;
1254 std::string banner;
1255
1256 bool has_component_ = false;
1257 bool has_launcher_category = false;
1258 bool has_leanback_launcher_category = false;
1259 bool has_main_action = false;
1260
1261 void Extract(xml::Element* element) override {
1262 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1263 label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
1264 icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
1265 banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
1266
1267 // Retrieve the package name from the manifest
1268 std::string package;
1269 for (auto& parent : extractor()->parent_stack()) {
1270 if (auto manifest = ElementCast<Manifest>(parent)) {
1271 package = manifest->package;
1272 break;
1273 }
1274 }
1275
1276 // Fully qualify the activity name
Chih-Hung Hsiehf2ef6572020-02-11 14:27:11 -08001277 ssize_t idx = name.find('.');
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001278 if (idx == 0) {
1279 name = package + name;
1280 } else if (idx < 0) {
1281 name = package + "." + name;
1282 }
1283
1284 auto orientation = GetAttributeInteger(FindAttribute(element, SCREEN_ORIENTATION_ATTR));
1285 if (orientation) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00001286 CommonFeatureGroup* common = extractor()->common_feature_group();
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001287 int orien = *orientation;
1288 if (orien == 0 || orien == 6 || orien == 8) {
1289 // Requests landscape, sensorLandscape, or reverseLandscape.
1290 common->addImpliedFeature("android.hardware.screen.landscape",
1291 "one or more activities have specified a landscape orientation",
1292 false);
1293 } else if (orien == 1 || orien == 7 || orien == 9) {
1294 // Requests portrait, sensorPortrait, or reversePortrait.
1295 common->addImpliedFeature("android.hardware.screen.portrait",
1296 "one or more activities have specified a portrait orientation",
1297 false);
1298 }
1299 }
1300 }
1301
Ryan Mitchell214846d2018-09-19 16:57:01 -07001302 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001303 // Print whether the activity has the HOME category and a the MAIN action
1304 if (has_main_action && has_launcher_category) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001305 printer->Print("launchable-activity:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001306 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001307 printer->Print(StringPrintf(" name='%s' ", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001308 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001309 printer->Print(StringPrintf(" label='%s' icon='%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001310 android::ResTable::normalizeForOutput(label.data()).c_str(),
1311 icon.data()));
1312 }
1313
1314 // Print wether the activity has the HOME category and a the MAIN action
1315 if (has_leanback_launcher_category) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001316 printer->Print("leanback-launchable-activity:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001317 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001318 printer->Print(StringPrintf(" name='%s' ", name.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001319 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001320 printer->Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001321 android::ResTable::normalizeForOutput(label.data()).c_str(),
1322 icon.data(), banner.data()));
1323 }
1324 }
1325};
1326
1327/** Represents <intent-filter> elements. */
1328class IntentFilter : public ManifestExtractor::Element {
1329 public:
1330 IntentFilter() = default;
1331};
1332
1333/** Represents <category> elements. */
1334class Category : public ManifestExtractor::Element {
1335 public:
1336 Category() = default;
1337 std::string component = "";
1338
1339 void Extract(xml::Element* element) override {
1340 const std::string* category = GetAttributeString(FindAttribute(element, NAME_ATTR));
1341
1342 auto parent_stack = extractor()->parent_stack();
1343 if (category && ElementCast<IntentFilter>(parent_stack[0])
1344 && ElementCast<Activity>(parent_stack[1])) {
1345 Activity* activity = ElementCast<Activity>(parent_stack[1]);
1346
1347 if (*category == "android.intent.category.LAUNCHER") {
1348 activity->has_launcher_category = true;
1349 } else if (*category == "android.intent.category.LEANBACK_LAUNCHER") {
1350 activity->has_leanback_launcher_category = true;
1351 } else if (*category == "android.intent.category.HOME") {
1352 component = "launcher";
1353 }
1354 }
1355 }
1356};
1357
1358/**
1359 * Represents <provider> elements. The elements may have an <intent-filter> which may have <action>
1360 * elements nested within.
1361 **/
1362class Provider : public ManifestExtractor::Element {
1363 public:
1364 Provider() = default;
1365 bool has_required_saf_attributes = false;
1366
1367 void Extract(xml::Element* element) override {
1368 const int32_t* exported = GetAttributeInteger(FindAttribute(element, EXPORTED_ATTR));
1369 const int32_t* grant_uri_permissions = GetAttributeInteger(
1370 FindAttribute(element, GRANT_URI_PERMISSIONS_ATTR));
1371 const std::string* permission = GetAttributeString(
1372 FindAttribute(element, PERMISSION_ATTR));
1373
1374 has_required_saf_attributes = ((exported && *exported != 0)
1375 && (grant_uri_permissions && *grant_uri_permissions != 0)
1376 && (permission && *permission == "android.permission.MANAGE_DOCUMENTS"));
1377 }
1378};
1379
1380/** Represents <receiver> elements. **/
1381class Receiver : public ManifestExtractor::Element {
1382 public:
1383 Receiver() = default;
1384 const std::string* permission = nullptr;
1385 bool has_component = false;
1386
1387 void Extract(xml::Element* element) override {
1388 permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
1389 }
1390};
1391
1392/**Represents <service> elements. **/
1393class Service : public ManifestExtractor::Element {
1394 public:
1395 Service() = default;
1396 const std::string* permission = nullptr;
1397 bool has_component = false;
1398
1399 void Extract(xml::Element* element) override {
1400 permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
1401 }
1402};
1403
1404/** Represents <uses-library> elements. **/
1405class UsesLibrary : public ManifestExtractor::Element {
1406 public:
1407 UsesLibrary() = default;
1408 std::string name;
1409 int required;
1410
1411 void Extract(xml::Element* element) override {
1412 auto parent_stack = extractor()->parent_stack();
1413 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1414 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1415 required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
1416 }
1417 }
1418
Ryan Mitchell214846d2018-09-19 16:57:01 -07001419 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001420 if (!name.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001421 printer->Print(StringPrintf("uses-library%s:'%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001422 (required == 0) ? "-not-required" : "", name.data()));
1423 }
1424 }
1425};
1426
Dianne Hackborn813d7502018-10-02 16:59:46 -07001427/** Represents <static-library> elements. **/
1428class StaticLibrary : public ManifestExtractor::Element {
1429 public:
1430 StaticLibrary() = default;
1431 std::string name;
1432 int version;
1433 int versionMajor;
1434
1435 void Extract(xml::Element* element) override {
1436 auto parent_stack = extractor()->parent_stack();
1437 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1438 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1439 version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
1440 versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
1441 }
1442 }
1443
Ryan Mitchell214846d2018-09-19 16:57:01 -07001444 void Print(text::Printer* printer) override {
1445 printer->Print(StringPrintf(
Dianne Hackborn813d7502018-10-02 16:59:46 -07001446 "static-library: name='%s' version='%d' versionMajor='%d'\n",
1447 name.data(), version, versionMajor));
1448 }
1449};
1450
1451/** Represents <uses-static-library> elements. **/
1452class UsesStaticLibrary : public ManifestExtractor::Element {
1453 public:
1454 UsesStaticLibrary() = default;
1455 std::string name;
1456 int version;
1457 int versionMajor;
1458 std::vector<std::string> certDigests;
1459
1460 void Extract(xml::Element* element) override {
1461 auto parent_stack = extractor()->parent_stack();
1462 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1463 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1464 version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
1465 versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
1466 AddCertDigest(element);
1467 }
1468 }
1469
1470 void AddCertDigest(xml::Element* element) {
1471 std::string digest = GetAttributeStringDefault(FindAttribute(element, CERT_DIGEST_ATTR), "");
1472 // We allow ":" delimiters in the SHA declaration as this is the format
1473 // emitted by the certtool making it easy for developers to copy/paste.
1474 digest.erase(std::remove(digest.begin(), digest.end(), ':'), digest.end());
1475 if (!digest.empty()) {
1476 certDigests.push_back(digest);
1477 }
1478 }
1479
Ryan Mitchell214846d2018-09-19 16:57:01 -07001480 void Print(text::Printer* printer) override {
1481 printer->Print(StringPrintf(
Dianne Hackborn813d7502018-10-02 16:59:46 -07001482 "uses-static-library: name='%s' version='%d' versionMajor='%d'",
1483 name.data(), version, versionMajor));
1484 for (size_t i = 0; i < certDigests.size(); i++) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001485 printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
Dianne Hackborn813d7502018-10-02 16:59:46 -07001486 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001487 printer->Print("\n");
Dianne Hackborn813d7502018-10-02 16:59:46 -07001488 }
1489};
1490
Alex Buynytskyya16137052021-12-02 13:26:54 +00001491/** Represents <sdk-library> elements. **/
1492class SdkLibrary : public ManifestExtractor::Element {
1493 public:
1494 SdkLibrary() = default;
1495 std::string name;
1496 int versionMajor;
1497
1498 void Extract(xml::Element* element) override {
1499 auto parent_stack = extractor()->parent_stack();
1500 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1501 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1502 versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
1503 }
1504 }
1505
1506 void Print(text::Printer* printer) override {
1507 printer->Print(
1508 StringPrintf("sdk-library: name='%s' versionMajor='%d'\n", name.data(), versionMajor));
1509 }
1510};
1511
1512/** Represents <uses-sdk-library> elements. **/
1513class UsesSdkLibrary : public ManifestExtractor::Element {
1514 public:
1515 UsesSdkLibrary() = default;
1516 std::string name;
1517 int versionMajor;
1518 std::vector<std::string> certDigests;
1519
1520 void Extract(xml::Element* element) override {
1521 auto parent_stack = extractor()->parent_stack();
1522 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1523 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1524 versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
1525 AddCertDigest(element);
1526 }
1527 }
1528
1529 void AddCertDigest(xml::Element* element) {
1530 std::string digest = GetAttributeStringDefault(FindAttribute(element, CERT_DIGEST_ATTR), "");
1531 // We allow ":" delimiters in the SHA declaration as this is the format
1532 // emitted by the certtool making it easy for developers to copy/paste.
1533 digest.erase(std::remove(digest.begin(), digest.end(), ':'), digest.end());
1534 if (!digest.empty()) {
1535 certDigests.push_back(digest);
1536 }
1537 }
1538
1539 void Print(text::Printer* printer) override {
1540 printer->Print(
1541 StringPrintf("uses-sdk-library: name='%s' versionMajor='%d'", name.data(), versionMajor));
1542 for (size_t i = 0; i < certDigests.size(); i++) {
1543 printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
1544 }
1545 printer->Print("\n");
1546 }
1547};
1548
Jiyong Park6a5b8b12020-06-30 13:23:36 +09001549/** Represents <uses-native-library> elements. **/
1550class UsesNativeLibrary : public ManifestExtractor::Element {
1551 public:
1552 UsesNativeLibrary() = default;
1553 std::string name;
1554 int required;
1555
1556 void Extract(xml::Element* element) override {
1557 auto parent_stack = extractor()->parent_stack();
1558 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1559 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1560 required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
1561 }
1562 }
1563
1564 void Print(text::Printer* printer) override {
1565 if (!name.empty()) {
1566 printer->Print(StringPrintf("uses-native-library%s:'%s'\n",
1567 (required == 0) ? "-not-required" : "", name.data()));
1568 }
1569 }
1570};
1571
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001572/**
1573 * Represents <meta-data> elements. These tags are only printed when a flag is passed in to
1574 * explicitly enable meta data printing.
1575 **/
1576class MetaData : public ManifestExtractor::Element {
1577 public:
1578 MetaData() = default;
1579 std::string name;
Ryan Mitchell2250c932018-10-04 11:07:40 -07001580 std::string value;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001581 const int* value_int;
Ryan Mitchell2250c932018-10-04 11:07:40 -07001582 std::string resource;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001583 const int* resource_int;
1584
1585 void Extract(xml::Element* element) override {
1586 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
Ryan Mitchell2250c932018-10-04 11:07:40 -07001587 value = GetAttributeStringDefault(FindAttribute(element, VALUE_ATTR), "");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001588 value_int = GetAttributeInteger(FindAttribute(element, VALUE_ATTR));
Ryan Mitchell2250c932018-10-04 11:07:40 -07001589 resource = GetAttributeStringDefault(FindAttribute(element, RESOURCE_ATTR), "");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001590 resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR));
1591 }
1592
Ryan Mitchell214846d2018-09-19 16:57:01 -07001593 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001594 if (extractor()->options_.include_meta_data && !name.empty()) {
Iurii Makhnodcead622022-04-13 18:00:03 +00001595 printer->Print(StringPrintf("meta-data: name='%s'", name.data()));
Ryan Mitchell2250c932018-10-04 11:07:40 -07001596 if (!value.empty()) {
Iurii Makhnodcead622022-04-13 18:00:03 +00001597 printer->Print(StringPrintf(" value='%s'", value.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001598 } else if (value_int) {
Iurii Makhnodcead622022-04-13 18:00:03 +00001599 printer->Print(StringPrintf(" value='%d'", *value_int));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001600 } else {
Ryan Mitchell2250c932018-10-04 11:07:40 -07001601 if (!resource.empty()) {
Iurii Makhnodcead622022-04-13 18:00:03 +00001602 printer->Print(StringPrintf(" resource='%s'", resource.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001603 } else if (resource_int) {
Iurii Makhnodcead622022-04-13 18:00:03 +00001604 printer->Print(StringPrintf(" resource='%d'", *resource_int));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001605 }
1606 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001607 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001608 }
1609 }
1610};
1611
1612/**
1613 * Represents <action> elements. Detects the presence of certain activity, provider, receiver, and
1614 * service components.
1615 **/
1616class Action : public ManifestExtractor::Element {
1617 public:
1618 Action() = default;
1619 std::string component = "";
1620
1621 void Extract(xml::Element* element) override {
1622 auto parent_stack = extractor()->parent_stack();
1623 std::string action = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1624
1625 if (ElementCast<IntentFilter>(parent_stack[0])) {
1626 if (ElementCast<Activity>(parent_stack[1])) {
1627 // Detects the presence of a particular type of activity.
1628 Activity* activity = ElementCast<Activity>(parent_stack[1]);
1629 auto map = std::map<std::string, std::string>({
1630 { "android.intent.action.MAIN" , "main" },
1631 { "android.intent.action.VIDEO_CAMERA" , "camera" },
1632 { "android.intent.action.STILL_IMAGE_CAMERA_SECURE" , "camera-secure" },
1633 });
1634
1635 auto entry = map.find(action);
1636 if (entry != map.end()) {
1637 component = entry->second;
1638 activity->has_component_ = true;
1639 }
1640
1641 if (action == "android.intent.action.MAIN") {
1642 activity->has_main_action = true;
1643 }
1644
1645 } else if (ElementCast<Receiver>(parent_stack[1])) {
1646 // Detects the presence of a particular type of receiver. If the action requires a
1647 // permission, then the receiver element is checked for the permission.
1648 Receiver* receiver = ElementCast<Receiver>(parent_stack[1]);
1649 auto map = std::map<std::string, std::string>({
1650 { "android.appwidget.action.APPWIDGET_UPDATE" , "app-widget" },
1651 { "android.app.action.DEVICE_ADMIN_ENABLED" , "device-admin" },
1652 });
1653
1654 auto permissions = std::map<std::string, std::string>({
1655 { "android.app.action.DEVICE_ADMIN_ENABLED" , "android.permission.BIND_DEVICE_ADMIN" },
1656 });
1657
1658 auto entry = map.find(action);
1659 auto permission = permissions.find(action);
1660 if (entry != map.end() && (permission == permissions.end()
1661 || (receiver->permission && permission->second == *receiver->permission))) {
1662 receiver->has_component = true;
1663 component = entry->second;
1664 }
1665
1666 } else if (ElementCast<Service>(parent_stack[1])) {
1667 // Detects the presence of a particular type of service. If the action requires a
1668 // permission, then the service element is checked for the permission.
1669 Service* service = ElementCast<Service>(parent_stack[1]);
1670 auto map = std::map<std::string, std::string>({
1671 { "android.view.InputMethod" , "ime" },
1672 { "android.service.wallpaper.WallpaperService" , "wallpaper" },
1673 { "android.accessibilityservice.AccessibilityService" , "accessibility" },
1674 { "android.printservice.PrintService" , "print-service" },
1675 { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" , "host-apdu" },
1676 { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" , "offhost-apdu" },
1677 { "android.service.notification.NotificationListenerService" ,"notification-listener" },
1678 { "android.service.dreams.DreamService" , "dream" },
1679 });
1680
1681 auto permissions = std::map<std::string, std::string>({
1682 { "android.accessibilityservice.AccessibilityService" ,
1683 "android.permission.BIND_ACCESSIBILITY_SERVICE" },
1684 { "android.printservice.PrintService" , "android.permission.BIND_PRINT_SERVICE" },
1685 { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" ,
1686 "android.permission.BIND_NFC_SERVICE" },
1687 { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" ,
1688 "android.permission.BIND_NFC_SERVICE" },
1689 { "android.service.notification.NotificationListenerService" ,
1690 "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" },
1691 { "android.service.dreams.DreamService" , "android.permission.BIND_DREAM_SERVICE" },
1692 });
1693
1694 auto entry = map.find(action);
1695 auto permission = permissions.find(action);
1696 if (entry != map.end() && (permission == permissions.end()
1697 || (service->permission && permission->second == *service->permission))) {
1698 service->has_component= true;
1699 component = entry->second;
1700 }
1701
1702 } else if (ElementCast<Provider>(parent_stack[1])) {
1703 // Detects the presence of a particular type of receiver. If the provider requires a
1704 // permission, then the provider element is checked for the permission.
1705 // Detect whether this action
1706 Provider* provider = ElementCast<Provider>(parent_stack[1]);
1707 if (action == "android.content.action.DOCUMENTS_PROVIDER"
1708 && provider->has_required_saf_attributes) {
1709 component = "document-provider";
1710 }
1711 }
1712 }
1713
1714 // Represents a searchable interface
1715 if (action == "android.intent.action.SEARCH") {
1716 component = "search";
1717 }
1718 }
1719};
1720
1721/**
1722 * Represents <supports-input> elements. The element may have <input-type> elements nested within.
1723 **/
1724class SupportsInput : public ManifestExtractor::Element {
1725 public:
1726 SupportsInput() = default;
1727 std::vector<std::string> inputs;
1728
Ryan Mitchell214846d2018-09-19 16:57:01 -07001729 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001730 const size_t size = inputs.size();
1731 if (size > 0) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001732 printer->Print("supports-input: '");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001733 for (size_t i = 0; i < size; i++) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001734 printer->Print(StringPrintf("value='%s' ", inputs[i].data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001735 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001736 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001737 }
1738 }
1739};
1740
1741/** Represents <input-type> elements. **/
1742class InputType : public ManifestExtractor::Element {
1743 public:
1744 InputType() = default;
1745 void Extract(xml::Element* element) override {
1746 auto name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1747 auto parent_stack = extractor()->parent_stack();
1748
1749 // Add the input to the set of supported inputs
1750 if (name && ElementCast<SupportsInput>(parent_stack[0])) {
1751 SupportsInput* supports = ElementCast<SupportsInput>(parent_stack[0]);
1752 supports->inputs.push_back(*name);
1753 }
1754 }
1755};
1756
1757/** Represents <original-package> elements. **/
1758class OriginalPackage : public ManifestExtractor::Element {
1759 public:
1760 OriginalPackage() = default;
1761 const std::string* name = nullptr;
1762
1763 void Extract(xml::Element* element) override {
1764 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1765 }
1766
Ryan Mitchell214846d2018-09-19 16:57:01 -07001767 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001768 if (name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001769 printer->Print(StringPrintf("original-package:'%s'\n", name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001770 }
1771 }
1772};
1773
Anton Hanssoncd2d8e22018-12-11 13:52:17 +00001774
1775/** Represents <overlay> elements. **/
1776class Overlay : public ManifestExtractor::Element {
1777 public:
1778 Overlay() = default;
1779 const std::string* target_package = nullptr;
1780 int priority;
1781 bool is_static;
1782 const std::string* required_property_name = nullptr;
1783 const std::string* required_property_value = nullptr;
1784
1785 void Extract(xml::Element* element) override {
1786 target_package = GetAttributeString(FindAttribute(element, TARGET_PACKAGE_ATTR));
1787 priority = GetAttributeIntegerDefault(FindAttribute(element, PRIORITY_ATTR), 0);
1788 is_static = GetAttributeIntegerDefault(FindAttribute(element, IS_STATIC_ATTR), false) != 0;
1789 required_property_name = GetAttributeString(
1790 FindAttribute(element, REQUIRED_SYSTEM_PROPERTY_NAME_ATTR));
1791 required_property_value = GetAttributeString(
1792 FindAttribute(element, REQUIRED_SYSTEM_PROPERTY_VALUE_ATTR));
1793 }
1794
1795 void Print(text::Printer* printer) override {
1796 printer->Print(StringPrintf("overlay:"));
1797 if (target_package) {
1798 printer->Print(StringPrintf(" targetPackage='%s'", target_package->c_str()));
1799 }
1800 printer->Print(StringPrintf(" priority='%d'", priority));
1801 printer->Print(StringPrintf(" isStatic='%s'", is_static ? "true" : "false"));
1802 if (required_property_name) {
1803 printer->Print(StringPrintf(" requiredPropertyName='%s'", required_property_name->c_str()));
1804 }
1805 if (required_property_value) {
1806 printer->Print(StringPrintf(" requiredPropertyValue='%s'", required_property_value->c_str()));
1807 }
1808 printer->Print("\n");
1809 }
1810};
1811
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001812/** * Represents <package-verifier> elements. **/
1813class PackageVerifier : public ManifestExtractor::Element {
1814 public:
1815 PackageVerifier() = default;
1816 const std::string* name = nullptr;
1817 const std::string* public_key = nullptr;
1818
1819 void Extract(xml::Element* element) override {
1820 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1821 public_key = GetAttributeString(FindAttribute(element, PUBLIC_KEY_ATTR));
1822 }
1823
Ryan Mitchell214846d2018-09-19 16:57:01 -07001824 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001825 if (name && public_key) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001826 printer->Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n",
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001827 name->data(), public_key->data()));
1828 }
1829 }
1830};
1831
1832/** Represents <uses-package> elements. **/
1833class UsesPackage : public ManifestExtractor::Element {
1834 public:
1835 UsesPackage() = default;
Dianne Hackborn813d7502018-10-02 16:59:46 -07001836 const std::string* packageType = nullptr;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001837 const std::string* name = nullptr;
Dianne Hackborn813d7502018-10-02 16:59:46 -07001838 int version;
1839 int versionMajor;
1840 std::vector<std::string> certDigests;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001841
1842 void Extract(xml::Element* element) override {
Dianne Hackborn813d7502018-10-02 16:59:46 -07001843 auto parent_stack = extractor()->parent_stack();
1844 if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
1845 packageType = GetAttributeString(FindAttribute(element, PACKAGE_TYPE_ATTR));
1846 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1847 version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
1848 versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
1849 AddCertDigest(element);
1850 }
1851 }
1852
1853 void AddCertDigest(xml::Element* element) {
1854 std::string digest = GetAttributeStringDefault(FindAttribute(element, CERT_DIGEST_ATTR), "");
1855 // We allow ":" delimiters in the SHA declaration as this is the format
1856 // emitted by the certtool making it easy for developers to copy/paste.
1857 digest.erase(std::remove(digest.begin(), digest.end(), ':'), digest.end());
1858 if (!digest.empty()) {
1859 certDigests.push_back(digest);
1860 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001861 }
1862
Ryan Mitchell214846d2018-09-19 16:57:01 -07001863 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001864 if (name) {
Dianne Hackborn813d7502018-10-02 16:59:46 -07001865 if (packageType) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001866 printer->Print(StringPrintf(
Dianne Hackborn813d7502018-10-02 16:59:46 -07001867 "uses-typed-package: type='%s' name='%s' version='%d' versionMajor='%d'",
1868 packageType->data(), name->data(), version, versionMajor));
1869 for (size_t i = 0; i < certDigests.size(); i++) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001870 printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
Dianne Hackborn813d7502018-10-02 16:59:46 -07001871 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07001872 printer->Print("\n");
Dianne Hackborn813d7502018-10-02 16:59:46 -07001873 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001874 printer->Print(StringPrintf("uses-package:'%s'\n", name->data()));
Dianne Hackborn813d7502018-10-02 16:59:46 -07001875 }
1876 }
1877 }
1878};
1879
1880/** Represents <additional-certificate> elements. **/
1881class AdditionalCertificate : public ManifestExtractor::Element {
1882 public:
1883 AdditionalCertificate() = default;
1884
1885 void Extract(xml::Element* element) override {
1886 auto parent_stack = extractor()->parent_stack();
1887 if (parent_stack.size() > 0) {
1888 if (ElementCast<UsesPackage>(parent_stack[0])) {
1889 UsesPackage* uses = ElementCast<UsesPackage>(parent_stack[0]);
1890 uses->AddCertDigest(element);
1891 } else if (ElementCast<UsesStaticLibrary>(parent_stack[0])) {
1892 UsesStaticLibrary* uses = ElementCast<UsesStaticLibrary>(parent_stack[0]);
1893 uses->AddCertDigest(element);
1894 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001895 }
1896 }
1897};
1898
1899/** Represents <screen> elements found in <compatible-screens> elements. */
1900class Screen : public ManifestExtractor::Element {
1901 public:
1902 Screen() = default;
1903 const int32_t* size = nullptr;
1904 const int32_t* density = nullptr;
1905
1906 void Extract(xml::Element* element) override {
1907 size = GetAttributeInteger(FindAttribute(element, SCREEN_SIZE_ATTR));
1908 density = GetAttributeInteger(FindAttribute(element, SCREEN_DENSITY_ATTR));
1909 }
1910};
1911
1912/**
1913 * Represents <compatible-screens> elements. These elements have <screen> elements nested within
1914 * that each denote a supported screen size and screen density.
1915 **/
1916class CompatibleScreens : public ManifestExtractor::Element {
1917 public:
1918 CompatibleScreens() = default;
Ryan Mitchell214846d2018-09-19 16:57:01 -07001919 void Print(text::Printer* printer) override {
1920 printer->Print("compatible-screens:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001921
1922 bool first = true;
1923 ForEachChild(this, [&printer, &first](ManifestExtractor::Element* el){
1924 if (auto screen = ElementCast<Screen>(el)) {
1925 if (first) {
1926 first = false;
1927 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001928 printer->Print(",");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001929 }
1930
1931 if (screen->size && screen->density) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001932 printer->Print(StringPrintf("'%d/%d'", *screen->size, *screen->density));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001933 }
1934 }
1935 });
Ryan Mitchell214846d2018-09-19 16:57:01 -07001936 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001937 }
1938};
1939
1940/** Represents <supports-gl-texture> elements. **/
1941class SupportsGlTexture : public ManifestExtractor::Element {
1942 public:
1943 SupportsGlTexture() = default;
1944 const std::string* name = nullptr;
1945
1946 void Extract(xml::Element* element) override {
1947 name = GetAttributeString(FindAttribute(element, NAME_ATTR));
1948 }
1949
Ryan Mitchell214846d2018-09-19 16:57:01 -07001950 void Print(text::Printer* printer) override {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001951 if (name) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07001952 printer->Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07001953 }
1954 }
1955};
1956
Todd Kennedyce3e1292020-10-29 17:14:24 -07001957/** Represents <property> elements. **/
1958class Property : public ManifestExtractor::Element {
1959 public:
1960 Property() = default;
1961 std::string name;
1962 std::string value;
1963 const int* value_int;
1964 std::string resource;
1965 const int* resource_int;
1966
1967 void Extract(xml::Element* element) override {
1968 name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
1969 value = GetAttributeStringDefault(FindAttribute(element, VALUE_ATTR), "");
1970 value_int = GetAttributeInteger(FindAttribute(element, VALUE_ATTR));
1971 resource = GetAttributeStringDefault(FindAttribute(element, RESOURCE_ATTR), "");
1972 resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR));
1973 }
1974
1975 void Print(text::Printer* printer) override {
1976 printer->Print(StringPrintf("property: name='%s' ", name.data()));
1977 if (!value.empty()) {
1978 printer->Print(StringPrintf("value='%s' ", value.data()));
1979 } else if (value_int) {
1980 printer->Print(StringPrintf("value='%d' ", *value_int));
1981 } else {
1982 if (!resource.empty()) {
1983 printer->Print(StringPrintf("resource='%s' ", resource.data()));
1984 } else if (resource_int) {
1985 printer->Print(StringPrintf("resource='%d' ", *resource_int));
1986 }
1987 }
1988 printer->Print("\n");
1989 }
1990};
1991
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00001992class Architectures {
1993 public:
1994 std::set<std::string> architectures;
1995 std::set<std::string> alt_architectures;
1996
1997 void Print(text::Printer* printer) {
1998 if (!architectures.empty()) {
1999 printer->Print("native-code:");
2000 for (auto& arch : architectures) {
2001 printer->Print(StringPrintf(" '%s'", arch.data()));
2002 }
2003 printer->Print("\n");
2004 }
2005 if (!alt_architectures.empty()) {
2006 printer->Print("alt-native-code:");
2007 for (auto& arch : alt_architectures) {
2008 printer->Print(StringPrintf(" '%s'", arch.data()));
2009 }
2010 printer->Print("\n");
2011 }
2012 }
2013};
2014
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002015/** Recursively prints the extracted badging element. */
Ryan Mitchell214846d2018-09-19 16:57:01 -07002016static void Print(ManifestExtractor::Element* el, text::Printer* printer) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002017 el->Print(printer);
2018 for (auto &child : el->children()) {
2019 Print(child.get(), printer);
2020 }
2021}
2022
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002023bool ManifestExtractor::Extract(IDiagnostics* diag) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002024 // Load the manifest
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002025 doc_ = apk_->LoadXml("AndroidManifest.xml", diag);
2026 if (doc_ == nullptr) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002027 diag->Error(DiagMessage() << "failed to find AndroidManifest.xml");
2028 return false;
2029 }
2030
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002031 xml::Element* element = doc_->root.get();
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002032 if (element->name != "manifest") {
2033 diag->Error(DiagMessage() << "manifest does not start with <manifest> tag");
2034 return false;
2035 }
2036
2037 // Print only the <uses-permission>, <uses-permission-sdk23>, and <permission> elements if
2038 // printing only permission elements is requested
2039 if (options_.only_permissions) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002040 root_element_ = ManifestExtractor::Element::Inflate(this, element);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002041
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002042 if (auto manifest = ElementCast<Manifest>(root_element_.get())) {
2043 manifest->only_package_name = true;
2044
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002045 for (xml::Element* child : element->GetChildElements()) {
2046 if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
2047 || child->name == "permission") {
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002048 // Inflate the element and its descendants
2049 auto permission_element = Visit(child);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002050 manifest->AddChild(permission_element);
2051 }
2052 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002053 return true;
2054 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002055 return false;
2056 }
2057
2058 // Collect information about the resource configurations
2059 if (apk_->GetResourceTable()) {
2060 for (auto &package : apk_->GetResourceTable()->packages) {
2061 for (auto &type : package->types) {
2062 for (auto &entry : type->entries) {
2063 for (auto &value : entry->values) {
2064 std::string locale_str = value->config.GetBcp47LanguageTag();
2065
2066 // Collect all the unique locales of the apk
2067 if (locales_.find(locale_str) == locales_.end()) {
Ryan Mitchell4ea90752020-07-31 08:21:43 -07002068 ConfigDescription config = ManifestExtractor::DefaultConfig();
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002069 config.setBcp47Locale(locale_str.data());
2070 locales_.insert(std::make_pair(locale_str, config));
2071 }
2072
2073 // Collect all the unique density of the apk
2074 uint16_t density = (value->config.density == 0) ? (uint16_t) 160
2075 : value->config.density;
2076 if (densities_.find(density) == densities_.end()) {
Ryan Mitchell4ea90752020-07-31 08:21:43 -07002077 ConfigDescription config = ManifestExtractor::DefaultConfig();
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002078 config.density = density;
2079 densities_.insert(std::make_pair(density, config));
2080 }
2081 }
2082 }
2083 }
2084 }
2085 }
2086
2087 // Extract badging information
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002088 root_element_ = Visit(element);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002089
Ryan Mitchell1966e1f2021-05-03 13:46:56 -07002090 // Filter out all "uses-sdk" tags besides the very last tag. The android runtime only uses the
2091 // attribute values from the last defined tag.
2092 std::vector<UsesSdkBadging*> filtered_uses_sdk_tags;
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002093 for (const auto& child : root_element_->children()) {
Ryan Mitchell1966e1f2021-05-03 13:46:56 -07002094 if (auto uses_sdk = ElementCast<UsesSdkBadging>(child.get())) {
2095 filtered_uses_sdk_tags.emplace_back(uses_sdk);
2096 }
2097 }
Ryan Mitchell6ea9ed32021-05-20 11:38:57 -07002098 if (filtered_uses_sdk_tags.size() >= 2U) {
2099 filtered_uses_sdk_tags.pop_back();
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002100 root_element_->Filter([&](const ManifestExtractor::Element* e) {
Ryan Mitchell6ea9ed32021-05-20 11:38:57 -07002101 return std::find(filtered_uses_sdk_tags.begin(), filtered_uses_sdk_tags.end(), e) !=
2102 filtered_uses_sdk_tags.end();
2103 });
2104 }
Ryan Mitchell1966e1f2021-05-03 13:46:56 -07002105
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002106 /** Recursively checks the extracted elements for the specified permission. **/
2107 auto FindPermission = [&](ManifestExtractor::Element* root,
2108 const std::string& name) -> ManifestExtractor::Element* {
2109 return FindElement(root, [&](ManifestExtractor::Element* el) -> bool {
2110 if (UsesPermission* permission = ElementCast<UsesPermission>(el)) {
2111 return permission->name == name;
2112 }
2113 return false;
2114 });
2115 };
2116
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002117 auto AddImpliedPermission = [&](const std::string& name, const std::string& reason,
2118 int32_t max_sdk_version) -> void {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002119 auto permission = util::make_unique<UsesPermission>();
2120 permission->name = name;
2121 permission->maxSdkVersion = max_sdk_version;
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002122 permission->implied = true;
2123 permission->impliedReason = reason;
2124 implied_permissions_.push_back(std::move(permission));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002125 };
2126
2127 // Implied permissions
2128 // Pre-1.6 implicitly granted permission compatibility logic
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002129 bool insert_write_external = false;
2130 auto write_external_permission = ElementCast<UsesPermission>(
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002131 FindPermission(root_element_.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002132
Jackal Guo201a60a2021-08-31 12:37:30 +08002133 if (target_sdk() < SDK_DONUT) {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002134 if (!write_external_permission) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002135 AddImpliedPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002136 insert_write_external = true;
2137 }
2138
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002139 if (!FindPermission(root_element_.get(), "android.permission.READ_PHONE_STATE")) {
2140 AddImpliedPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002141 }
2142 }
2143
2144 // If the application has requested WRITE_EXTERNAL_STORAGE, we will
2145 // force them to always take READ_EXTERNAL_STORAGE as well. We always
2146 // do this (regardless of target API version) because we can't have
2147 // an app with write permission but not read permission.
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002148 auto read_external =
2149 FindPermission(root_element_.get(), "android.permission.READ_EXTERNAL_STORAGE");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002150 if (!read_external && (insert_write_external || write_external_permission)) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002151 AddImpliedPermission(
2152 "android.permission.READ_EXTERNAL_STORAGE", "requested WRITE_EXTERNAL_STORAGE",
2153 (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002154 }
2155
2156 // Pre-JellyBean call log permission compatibility.
Jackal Guo201a60a2021-08-31 12:37:30 +08002157 if (target_sdk() < SDK_JELLY_BEAN) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002158 if (!FindPermission(root_element_.get(), "android.permission.READ_CALL_LOG") &&
2159 FindPermission(root_element_.get(), "android.permission.READ_CONTACTS")) {
2160 AddImpliedPermission("android.permission.READ_CALL_LOG",
2161 "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002162 }
2163
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002164 if (!FindPermission(root_element_.get(), "android.permission.WRITE_CALL_LOG") &&
2165 FindPermission(root_element_.get(), "android.permission.WRITE_CONTACTS")) {
2166 AddImpliedPermission("android.permission.WRITE_CALL_LOG",
2167 "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002168 }
2169 }
2170
2171 // If the app hasn't declared the touchscreen as a feature requirement (either
2172 // directly or implied, required or not), then the faketouch feature is implied.
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002173 if (!common_feature_group()->HasFeature("android.hardware.touchscreen")) {
2174 common_feature_group()->addImpliedFeature("android.hardware.faketouch",
2175 "default feature for all apps", false);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002176 }
2177
2178 // Only print the common feature group if no feature group is defined
2179 std::vector<FeatureGroup*> feature_groups;
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002180 ForEachChild(root_element_.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002181 if (auto feature_group = ElementCast<FeatureGroup>(el)) {
2182 feature_groups.push_back(feature_group);
2183 }
2184 });
2185
2186 if (feature_groups.empty()) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002187 feature_groups_.push_back(common_feature_group());
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002188 } else {
2189 // Merge the common feature group into the feature group
2190 for (auto& feature_group : feature_groups) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002191 feature_group->Merge(common_feature_group());
2192 feature_groups_.push_back(feature_group);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002193 }
2194 };
2195
2196 // Collect the component types of the application
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002197 ForEachChild(root_element_.get(), [&](ManifestExtractor::Element* el) -> void {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002198 if (ElementCast<Action>(el)) {
2199 auto action = ElementCast<Action>(el);
2200 if (!action->component.empty()) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002201 components_.insert(action->component);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002202 return;
2203 }
2204 }
2205
2206 if (ElementCast<Category>(el)) {
2207 auto category = ElementCast<Category>(el);
2208 if (!category->component.empty()) {
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002209 components_.insert(category->component);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002210 return;
2211 }
2212 }
2213 });
2214
2215 // Check for the payment component
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002216 ForEachChild(root_element_.get(), [this, &diag](ManifestExtractor::Element* el) -> void {
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002217 if (auto service = ElementCast<Service>(el)) {
2218 auto host_apdu_action = ElementCast<Action>(FindElement(service,
2219 [&](ManifestExtractor::Element* el) -> bool {
2220 if (auto action = ElementCast<Action>(el)) {
2221 return (action->component == "host-apdu");
2222 }
2223 return false;
2224 }));
2225
2226 auto offhost_apdu_action = ElementCast<Action>(FindElement(service,
2227 [&](ManifestExtractor::Element* el) -> bool {
2228 if (auto action = ElementCast<Action>(el)) {
2229 return (action->component == "offhost-apdu");
2230 }
2231 return false;
2232 }));
2233
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002234 ForEachChild(service,
2235 [this, &diag, &host_apdu_action,
2236 &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
2237 if (auto meta_data = ElementCast<MetaData>(el)) {
2238 if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" &&
2239 host_apdu_action) ||
2240 (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service" &&
2241 offhost_apdu_action)) {
2242 // Attempt to load the resource file
2243 if (!meta_data->resource.empty()) {
2244 return;
2245 }
2246 auto resource = this->apk_->LoadXml(meta_data->resource, diag);
2247 if (!resource) {
2248 return;
2249 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002250
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002251 // Look for the payment category on an <aid-group> element
2252 auto& root = resource.get()->root;
2253 if ((host_apdu_action && root->name == "host-apdu-service") ||
2254 (offhost_apdu_action && root->name == "offhost-apdu-service")) {
2255 for (auto& child : root->GetChildElements()) {
2256 if (child->name == "aid-group") {
2257 auto category = FindAttribute(child, CATEGORY_ATTR);
2258 if (category && category->value == "payment") {
2259 this->components_.insert("payment");
2260 return;
2261 }
2262 }
2263 }
2264 }
2265 }
2266 }
2267 });
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002268 }
2269 });
2270
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002271 // Print presence of activities, receivers, and services with no special components
2272 FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
2273 if (auto activity = ElementCast<Activity>(el)) {
2274 if (!activity->has_component_) {
2275 other_activities_ = true;
2276 return true;
2277 }
2278 }
2279 return false;
2280 });
2281
2282 FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
2283 if (auto receiver = ElementCast<Receiver>(el)) {
2284 if (!receiver->has_component) {
2285 other_receivers_ = true;
2286 return true;
2287 }
2288 }
2289 return false;
2290 });
2291
2292 FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
2293 if (auto service = ElementCast<Service>(el)) {
2294 if (!service->has_component) {
2295 other_services_ = true;
2296 return true;
2297 }
2298 }
2299 return false;
2300 });
2301
2302 // Gather the supported screens
2303 const static SupportsScreen default_screens{};
2304 SupportsScreen* screen = ElementCast<SupportsScreen>(
2305 FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
2306 return ElementCast<SupportsScreen>(el) != nullptr;
2307 }));
2308 supports_screen_ = screen ? screen : &default_screens;
2309
2310 // Gather the supported architectures_ of the app
2311 std::set<std::string> architectures_from_apk;
2312 auto it = apk_->GetFileCollection()->Iterator();
2313 while (it->HasNext()) {
2314 auto file_path = it->Next()->GetSource().path;
2315 size_t pos = file_path.find("lib/");
2316 if (pos != std::string::npos) {
2317 file_path = file_path.substr(pos + 4);
2318 pos = file_path.find('/');
2319 if (pos != std::string::npos) {
2320 file_path = file_path.substr(0, pos);
2321 }
2322
2323 architectures_from_apk.insert(file_path);
2324 }
2325 }
2326
2327 // Determine if the application has multiArch supports
2328 auto has_multi_arch =
2329 FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
2330 if (auto application = ElementCast<Application>(el)) {
2331 return application->has_multi_arch;
2332 }
2333 return false;
2334 });
2335
2336 bool output_alt_native_code = false;
2337 // A multiArch package is one that contains 64-bit and
2338 // 32-bit versions of native code and expects 3rd-party
2339 // apps to load these native code libraries. Since most
2340 // 64-bit systems also support 32-bit apps, the apps
2341 // loading this multiArch package's code may be either
2342 if (has_multi_arch) {
2343 // If this is a multiArch package, report the 64-bit
2344 // version only. Then as a separate entry, report the
2345 // rest.
2346 //
2347 // If we report the 32-bit architecture, this APK will
2348 // be installed on a 32-bit device, causing a large waste
2349 // of bandwidth and disk space. This assumes that
2350 // the developer of the multiArch package has also
2351 // made a version that is 32-bit only.
2352 const std::string kIntel64 = "x86_64";
2353 const std::string kArm64 = "arm64-v8a";
2354
2355 auto arch = architectures_from_apk.find(kIntel64);
2356 if (arch == architectures_from_apk.end()) {
2357 arch = architectures_from_apk.find(kArm64);
2358 }
2359
2360 if (arch != architectures_from_apk.end()) {
2361 architectures_->architectures.insert(*arch);
2362 architectures_from_apk.erase(arch);
2363 output_alt_native_code = true;
2364 }
2365 }
2366 for (auto& arch : architectures_from_apk) {
2367 if (output_alt_native_code) {
2368 architectures_->alt_architectures.insert(arch);
2369 } else {
2370 architectures_->architectures.insert(arch);
2371 }
2372 }
2373 return true;
2374}
2375
2376bool ManifestExtractor::Dump(text::Printer* printer) {
2377 Print(root_element_.get(), printer);
2378 if (options_.only_permissions) {
2379 return true;
2380 }
2381
2382 for (auto& implied_permission : implied_permissions_) {
2383 implied_permission->Print(printer);
2384 }
2385 for (auto& feature_group : feature_groups_) {
2386 feature_group->PrintGroup(printer);
2387 }
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002388 // Print the components types if they are present
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002389 auto& components = components_;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002390 auto PrintComponent = [&components, &printer](const std::string& component) -> void {
2391 if (components.find(component) != components.end()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002392 printer->Print(StringPrintf("provides-component:'%s'\n", component.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002393 }
2394 };
2395
2396 PrintComponent("app-widget");
2397 PrintComponent("device-admin");
2398 PrintComponent("ime");
2399 PrintComponent("wallpaper");
2400 PrintComponent("accessibility");
2401 PrintComponent("print-service");
2402 PrintComponent("payment");
2403 PrintComponent("search");
2404 PrintComponent("document-provider");
2405 PrintComponent("launcher");
2406 PrintComponent("notification-listener");
2407 PrintComponent("dream");
2408 PrintComponent("camera");
2409 PrintComponent("camera-secure");
2410
2411 // Print presence of main activity
2412 if (components.find("main") != components.end()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002413 printer->Print("main\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002414 }
2415
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002416 if (other_activities_) {
2417 printer->Print("other-activities\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002418 }
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002419 if (other_receivers_) {
2420 printer->Print("other-receivers\n");
2421 }
2422 if (other_services_) {
2423 printer->Print("other-services\n");
2424 }
2425 supports_screen_->PrintScreens(printer, target_sdk_);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002426
2427 // Print all the unique locales of the apk
Ryan Mitchell214846d2018-09-19 16:57:01 -07002428 printer->Print("locales:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002429 for (auto& config : locales_) {
2430 if (config.first.empty()) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002431 printer->Print(" '--_--'");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002432 } else {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002433 printer->Print(StringPrintf(" '%s'", config.first.data()));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002434 }
2435 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07002436 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002437
2438 // Print all the densities locales of the apk
Ryan Mitchell214846d2018-09-19 16:57:01 -07002439 printer->Print("densities:");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002440 for (auto& config : densities_) {
Ryan Mitchell214846d2018-09-19 16:57:01 -07002441 printer->Print(StringPrintf(" '%d'", config.first));
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002442 }
Ryan Mitchell214846d2018-09-19 16:57:01 -07002443 printer->Print("\n");
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002444
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002445 architectures_->Print(printer);
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002446 return true;
2447}
2448
2449/**
2450 * Returns the element casted to the type if the element is of that type. Otherwise, returns a null
2451 * pointer.
2452 **/
2453template<typename T>
2454T* ElementCast(ManifestExtractor::Element* element) {
2455 if (element == nullptr) {
2456 return nullptr;
2457 }
2458
2459 const std::unordered_map<std::string, bool> kTagCheck = {
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002460 {"action", std::is_base_of<Action, T>::value},
2461 {"activity", std::is_base_of<Activity, T>::value},
2462 {"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
2463 {"application", std::is_base_of<Application, T>::value},
2464 {"category", std::is_base_of<Category, T>::value},
2465 {"compatible-screens", std::is_base_of<CompatibleScreens, T>::value},
2466 {"feature-group", std::is_base_of<FeatureGroup, T>::value},
2467 {"input-type", std::is_base_of<InputType, T>::value},
2468 {"intent-filter", std::is_base_of<IntentFilter, T>::value},
2469 {"meta-data", std::is_base_of<MetaData, T>::value},
2470 {"manifest", std::is_base_of<Manifest, T>::value},
2471 {"original-package", std::is_base_of<OriginalPackage, T>::value},
2472 {"overlay", std::is_base_of<Overlay, T>::value},
2473 {"package-verifier", std::is_base_of<PackageVerifier, T>::value},
2474 {"permission", std::is_base_of<Permission, T>::value},
Todd Kennedyce3e1292020-10-29 17:14:24 -07002475 {"property", std::is_base_of<Property, T>::value},
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002476 {"provider", std::is_base_of<Provider, T>::value},
2477 {"receiver", std::is_base_of<Receiver, T>::value},
2478 {"required-feature", std::is_base_of<RequiredFeature, T>::value},
2479 {"required-not-feature", std::is_base_of<RequiredNotFeature, T>::value},
2480 {"screen", std::is_base_of<Screen, T>::value},
2481 {"service", std::is_base_of<Service, T>::value},
Alex Buynytskyya16137052021-12-02 13:26:54 +00002482 {"sdk-library", std::is_base_of<SdkLibrary, T>::value},
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002483 {"static-library", std::is_base_of<StaticLibrary, T>::value},
2484 {"supports-gl-texture", std::is_base_of<SupportsGlTexture, T>::value},
2485 {"supports-input", std::is_base_of<SupportsInput, T>::value},
2486 {"supports-screens", std::is_base_of<SupportsScreen, T>::value},
2487 {"uses-configuration", std::is_base_of<UsesConfiguarion, T>::value},
2488 {"uses-feature", std::is_base_of<UsesFeature, T>::value},
2489 {"uses-library", std::is_base_of<UsesLibrary, T>::value},
2490 {"uses-native-library", std::is_base_of<UsesNativeLibrary, T>::value},
2491 {"uses-package", std::is_base_of<UsesPackage, T>::value},
2492 {"uses-permission", std::is_base_of<UsesPermission, T>::value},
2493 {"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
2494 {"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
Alex Buynytskyya16137052021-12-02 13:26:54 +00002495 {"uses-sdk-library", std::is_base_of<UsesSdkLibrary, T>::value},
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002496 {"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002497 };
2498
2499 auto check = kTagCheck.find(element->tag());
2500 if (check != kTagCheck.end() && check->second) {
2501 return static_cast<T*>(element);
2502 }
2503 return nullptr;
2504}
2505
2506template<typename T>
2507std::unique_ptr<T> CreateType() {
2508 return std::move(util::make_unique<T>());
2509}
2510
2511std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
2512 ManifestExtractor* extractor, xml::Element* el) {
2513 const std::unordered_map<std::string,
2514 std::function<std::unique_ptr<ManifestExtractor::Element>()>>
2515 kTagCheck = {
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002516 {"action", &CreateType<Action>},
2517 {"activity", &CreateType<Activity>},
2518 {"additional-certificate", &CreateType<AdditionalCertificate>},
2519 {"application", &CreateType<Application>},
2520 {"category", &CreateType<Category>},
2521 {"compatible-screens", &CreateType<CompatibleScreens>},
2522 {"feature-group", &CreateType<FeatureGroup>},
2523 {"input-type", &CreateType<InputType>},
2524 {"intent-filter", &CreateType<IntentFilter>},
2525 {"manifest", &CreateType<Manifest>},
2526 {"meta-data", &CreateType<MetaData>},
2527 {"original-package", &CreateType<OriginalPackage>},
2528 {"overlay", &CreateType<Overlay>},
2529 {"package-verifier", &CreateType<PackageVerifier>},
2530 {"permission", &CreateType<Permission>},
Todd Kennedyce3e1292020-10-29 17:14:24 -07002531 {"property", &CreateType<Property>},
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002532 {"provider", &CreateType<Provider>},
2533 {"receiver", &CreateType<Receiver>},
2534 {"required-feature", &CreateType<RequiredFeature>},
2535 {"required-not-feature", &CreateType<RequiredNotFeature>},
2536 {"screen", &CreateType<Screen>},
2537 {"service", &CreateType<Service>},
Alex Buynytskyya16137052021-12-02 13:26:54 +00002538 {"sdk-library", &CreateType<SdkLibrary>},
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002539 {"static-library", &CreateType<StaticLibrary>},
2540 {"supports-gl-texture", &CreateType<SupportsGlTexture>},
2541 {"supports-input", &CreateType<SupportsInput>},
2542 {"supports-screens", &CreateType<SupportsScreen>},
2543 {"uses-configuration", &CreateType<UsesConfiguarion>},
2544 {"uses-feature", &CreateType<UsesFeature>},
2545 {"uses-library", &CreateType<UsesLibrary>},
2546 {"uses-native-library", &CreateType<UsesNativeLibrary>},
2547 {"uses-package", &CreateType<UsesPackage>},
2548 {"uses-permission", &CreateType<UsesPermission>},
2549 {"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
2550 {"uses-sdk", &CreateType<UsesSdkBadging>},
Alex Buynytskyya16137052021-12-02 13:26:54 +00002551 {"uses-sdk-library", &CreateType<UsesSdkLibrary>},
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +00002552 {"uses-static-library", &CreateType<UsesStaticLibrary>},
2553 };
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002554
2555 // Attempt to map the xml tag to a element inflater
2556 std::unique_ptr<ManifestExtractor::Element> element;
2557 auto check = kTagCheck.find(el->name);
2558 if (check != kTagCheck.end()) {
2559 element = check->second();
2560 } else {
2561 element = util::make_unique<ManifestExtractor::Element>();
2562 }
2563
2564 element->extractor_ = extractor;
2565 element->tag_ = el->name;
2566 element->Extract(el);
2567 return element;
2568}
2569
2570std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(xml::Element* el) {
2571 auto element = ManifestExtractor::Element::Inflate(this, el);
2572 parent_stack_.insert(parent_stack_.begin(), element.get());
2573
2574 // Process the element and recursively visit the children
2575 for (xml::Element* child : el->GetChildElements()) {
2576 auto v = Visit(child);
2577 element->AddChild(v);
2578 }
2579
2580 parent_stack_.erase(parent_stack_.begin());
2581 return element;
2582}
2583
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002584
Ryan Mitchell214846d2018-09-19 16:57:01 -07002585int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
2586 IDiagnostics* diag) {
2587 ManifestExtractor extractor(apk, options);
Iurii Makhnoa9c74c52022-04-12 15:04:12 +00002588 if (!extractor.Extract(diag)) {
2589 return 0;
2590 }
2591 return extractor.Dump(printer) ? 0 : 1;
Ryan Mitchellfc225b22018-08-21 14:52:51 -07002592}
2593
Mårten Kongstad24c9aa62018-06-20 08:46:41 +02002594} // namespace aapt