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