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