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