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