• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2006 The Android Open Source Project
3 //
4 // Android Asset Packaging Tool main entry point.
5 //
6 #include "AaptXml.h"
7 #include "ApkBuilder.h"
8 #include "Bundle.h"
9 #include "Images.h"
10 #include "Main.h"
11 #include "ResourceFilter.h"
12 #include "ResourceTable.h"
13 #include "XMLNode.h"
14 
15 #include <utils/Errors.h>
16 #include <utils/KeyedVector.h>
17 #include <utils/List.h>
18 #include <utils/Log.h>
19 #include <utils/SortedVector.h>
20 #include <utils/threads.h>
21 #include <utils/Vector.h>
22 
23 #include <errno.h>
24 #include <fcntl.h>
25 
26 #include <iostream>
27 #include <string>
28 #include <sstream>
29 
30 using namespace android;
31 
32 #ifndef AAPT_VERSION
33     #define AAPT_VERSION ""
34 #endif
35 
36 /*
37  * Show version info.  All the cool kids do it.
38  */
doVersion(Bundle * bundle)39 int doVersion(Bundle* bundle)
40 {
41     if (bundle->getFileSpecCount() != 0) {
42         printf("(ignoring extra arguments)\n");
43     }
44     printf("Android Asset Packaging Tool, v0.2-" AAPT_VERSION "\n");
45 
46     return 0;
47 }
48 
49 
50 /*
51  * Open the file read only.  The call fails if the file doesn't exist.
52  *
53  * Returns NULL on failure.
54  */
openReadOnly(const char * fileName)55 ZipFile* openReadOnly(const char* fileName)
56 {
57     ZipFile* zip;
58     status_t result;
59 
60     zip = new ZipFile;
61     result = zip->open(fileName, ZipFile::kOpenReadOnly);
62     if (result != NO_ERROR) {
63         if (result == NAME_NOT_FOUND) {
64             fprintf(stderr, "ERROR: '%s' not found\n", fileName);
65         } else if (result == PERMISSION_DENIED) {
66             fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
67         } else {
68             fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
69                 fileName);
70         }
71         delete zip;
72         return NULL;
73     }
74 
75     return zip;
76 }
77 
78 /*
79  * Open the file read-write.  The file will be created if it doesn't
80  * already exist and "okayToCreate" is set.
81  *
82  * Returns NULL on failure.
83  */
openReadWrite(const char * fileName,bool okayToCreate)84 ZipFile* openReadWrite(const char* fileName, bool okayToCreate)
85 {
86     ZipFile* zip = NULL;
87     status_t result;
88     int flags;
89 
90     flags = ZipFile::kOpenReadWrite;
91     if (okayToCreate) {
92         flags |= ZipFile::kOpenCreate;
93     }
94 
95     zip = new ZipFile;
96     result = zip->open(fileName, flags);
97     if (result != NO_ERROR) {
98         delete zip;
99         zip = NULL;
100         goto bail;
101     }
102 
103 bail:
104     return zip;
105 }
106 
107 
108 /*
109  * Return a short string describing the compression method.
110  */
compressionName(int method)111 const char* compressionName(int method)
112 {
113     if (method == ZipEntry::kCompressStored) {
114         return "Stored";
115     } else if (method == ZipEntry::kCompressDeflated) {
116         return "Deflated";
117     } else {
118         return "Unknown";
119     }
120 }
121 
122 /*
123  * Return the percent reduction in size (0% == no compression).
124  */
calcPercent(long uncompressedLen,long compressedLen)125 int calcPercent(long uncompressedLen, long compressedLen)
126 {
127     if (!uncompressedLen) {
128         return 0;
129     } else {
130         return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
131     }
132 }
133 
134 /*
135  * Handle the "list" command, which can be a simple file dump or
136  * a verbose listing.
137  *
138  * The verbose listing closely matches the output of the Info-ZIP "unzip"
139  * command.
140  */
doList(Bundle * bundle)141 int doList(Bundle* bundle)
142 {
143     int result = 1;
144     ZipFile* zip = NULL;
145     const ZipEntry* entry;
146     long totalUncLen, totalCompLen;
147     const char* zipFileName;
148 
149     if (bundle->getFileSpecCount() != 1) {
150         fprintf(stderr, "ERROR: specify zip file name (only)\n");
151         goto bail;
152     }
153     zipFileName = bundle->getFileSpecEntry(0);
154 
155     zip = openReadOnly(zipFileName);
156     if (zip == NULL) {
157         goto bail;
158     }
159 
160     int count, i;
161 
162     if (bundle->getVerbose()) {
163         printf("Archive:  %s\n", zipFileName);
164         printf(
165             " Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name\n");
166         printf(
167             "--------  ------  ------- -----  -------      ----  ----  ------    ----\n");
168     }
169 
170     totalUncLen = totalCompLen = 0;
171 
172     count = zip->getNumEntries();
173     for (i = 0; i < count; i++) {
174         entry = zip->getEntryByIndex(i);
175         if (bundle->getVerbose()) {
176             char dateBuf[32];
177             time_t when;
178 
179             when = entry->getModWhen();
180             strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
181                 localtime(&when));
182 
183             printf("%8ld  %-7.7s %7ld %3d%%  %8zd  %s  %08lx  %s\n",
184                 (long) entry->getUncompressedLen(),
185                 compressionName(entry->getCompressionMethod()),
186                 (long) entry->getCompressedLen(),
187                 calcPercent(entry->getUncompressedLen(),
188                             entry->getCompressedLen()),
189                 (size_t) entry->getLFHOffset(),
190                 dateBuf,
191                 entry->getCRC32(),
192                 entry->getFileName());
193         } else {
194             printf("%s\n", entry->getFileName());
195         }
196 
197         totalUncLen += entry->getUncompressedLen();
198         totalCompLen += entry->getCompressedLen();
199     }
200 
201     if (bundle->getVerbose()) {
202         printf(
203         "--------          -------  ---                            -------\n");
204         printf("%8ld          %7ld  %2d%%                            %d files\n",
205             totalUncLen,
206             totalCompLen,
207             calcPercent(totalUncLen, totalCompLen),
208             zip->getNumEntries());
209     }
210 
211     if (bundle->getAndroidList()) {
212         AssetManager assets;
213         if (!assets.addAssetPath(String8(zipFileName), NULL)) {
214             fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
215             goto bail;
216         }
217 
218 #ifdef __ANDROID__
219         static const bool kHaveAndroidOs = true;
220 #else
221         static const bool kHaveAndroidOs = false;
222 #endif
223         const ResTable& res = assets.getResources(false);
224         if (!kHaveAndroidOs) {
225             printf("\nResource table:\n");
226             res.print(false);
227         }
228 
229         Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
230                                                    Asset::ACCESS_BUFFER);
231         if (manifestAsset == NULL) {
232             printf("\nNo AndroidManifest.xml found.\n");
233         } else {
234             printf("\nAndroid manifest:\n");
235             ResXMLTree tree;
236             tree.setTo(manifestAsset->getBuffer(true),
237                        manifestAsset->getLength());
238             printXMLBlock(&tree);
239         }
240         delete manifestAsset;
241     }
242 
243     result = 0;
244 
245 bail:
246     delete zip;
247     return result;
248 }
249 
printResolvedResourceAttribute(const ResTable & resTable,const ResXMLTree & tree,uint32_t attrRes,const String8 & attrLabel,String8 * outError)250 static void printResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree,
251         uint32_t attrRes, const String8& attrLabel, String8* outError)
252 {
253     Res_value value;
254     AaptXml::getResolvedResourceAttribute(resTable, tree, attrRes, &value, outError);
255     if (*outError != "") {
256         *outError = "error print resolved resource attribute";
257         return;
258     }
259     if (value.dataType == Res_value::TYPE_STRING) {
260         String8 result = AaptXml::getResolvedAttribute(resTable, tree, attrRes, outError);
261         printf("%s='%s'", attrLabel.string(),
262                 ResTable::normalizeForOutput(result.string()).string());
263     } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
264             value.dataType <= Res_value::TYPE_LAST_INT) {
265         printf("%s='%d'", attrLabel.string(), value.data);
266     } else {
267         printf("%s='0x%x'", attrLabel.string(), (int)value.data);
268     }
269 }
270 
271 // These are attribute resource constants for the platform, as found
272 // in android.R.attr
273 enum {
274     LABEL_ATTR = 0x01010001,
275     ICON_ATTR = 0x01010002,
276     NAME_ATTR = 0x01010003,
277     PERMISSION_ATTR = 0x01010006,
278     EXPORTED_ATTR = 0x01010010,
279     GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
280     RESOURCE_ATTR = 0x01010025,
281     DEBUGGABLE_ATTR = 0x0101000f,
282     VALUE_ATTR = 0x01010024,
283     VERSION_CODE_ATTR = 0x0101021b,
284     VERSION_NAME_ATTR = 0x0101021c,
285     SCREEN_ORIENTATION_ATTR = 0x0101001e,
286     MIN_SDK_VERSION_ATTR = 0x0101020c,
287     MAX_SDK_VERSION_ATTR = 0x01010271,
288     REQ_TOUCH_SCREEN_ATTR = 0x01010227,
289     REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
290     REQ_HARD_KEYBOARD_ATTR = 0x01010229,
291     REQ_NAVIGATION_ATTR = 0x0101022a,
292     REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
293     TARGET_SDK_VERSION_ATTR = 0x01010270,
294     TEST_ONLY_ATTR = 0x01010272,
295     ANY_DENSITY_ATTR = 0x0101026c,
296     GL_ES_VERSION_ATTR = 0x01010281,
297     SMALL_SCREEN_ATTR = 0x01010284,
298     NORMAL_SCREEN_ATTR = 0x01010285,
299     LARGE_SCREEN_ATTR = 0x01010286,
300     XLARGE_SCREEN_ATTR = 0x010102bf,
301     REQUIRED_ATTR = 0x0101028e,
302     INSTALL_LOCATION_ATTR = 0x010102b7,
303     SCREEN_SIZE_ATTR = 0x010102ca,
304     SCREEN_DENSITY_ATTR = 0x010102cb,
305     REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
306     COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
307     LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
308     PUBLIC_KEY_ATTR = 0x010103a6,
309     CATEGORY_ATTR = 0x010103e8,
310     BANNER_ATTR = 0x10103f2,
311     ISGAME_ATTR = 0x10103f4,
312     REQUIRED_FEATURE_ATTR = 0x1010557,
313     REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
314 };
315 
getComponentName(String8 & pkgName,String8 & componentName)316 String8 getComponentName(String8 &pkgName, String8 &componentName) {
317     ssize_t idx = componentName.find(".");
318     String8 retStr(pkgName);
319     if (idx == 0) {
320         retStr += componentName;
321     } else if (idx < 0) {
322         retStr += ".";
323         retStr += componentName;
324     } else {
325         return componentName;
326     }
327     return retStr;
328 }
329 
printCompatibleScreens(ResXMLTree & tree,String8 * outError)330 static void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
331     size_t len;
332     ResXMLTree::event_code_t code;
333     int depth = 0;
334     bool first = true;
335     printf("compatible-screens:");
336     while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
337         if (code == ResXMLTree::END_TAG) {
338             depth--;
339             if (depth < 0) {
340                 break;
341             }
342             continue;
343         }
344         if (code != ResXMLTree::START_TAG) {
345             continue;
346         }
347         depth++;
348         const char16_t* ctag16 = tree.getElementName(&len);
349         if (ctag16 == NULL) {
350             *outError = "failed to get XML element name (bad string pool)";
351             return;
352         }
353         String8 tag(ctag16);
354         if (tag == "screen") {
355             int32_t screenSize = AaptXml::getIntegerAttribute(tree,
356                     SCREEN_SIZE_ATTR);
357             int32_t screenDensity = AaptXml::getIntegerAttribute(tree,
358                     SCREEN_DENSITY_ATTR);
359             if (screenSize > 0 && screenDensity > 0) {
360                 if (!first) {
361                     printf(",");
362                 }
363                 first = false;
364                 printf("'%d/%d'", screenSize, screenDensity);
365             }
366         }
367     }
368     printf("\n");
369 }
370 
printUsesPermission(const String8 & name,bool optional=false,int maxSdkVersion=-1,const String8 & requiredFeature=String8::empty (),const String8 & requiredNotFeature=String8::empty ())371 static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1,
372         const String8& requiredFeature = String8::empty(),
373         const String8& requiredNotFeature = String8::empty()) {
374     printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
375     if (maxSdkVersion != -1) {
376          printf(" maxSdkVersion='%d'", maxSdkVersion);
377     }
378     if (requiredFeature.length() > 0) {
379          printf(" requiredFeature='%s'", requiredFeature.string());
380     }
381     if (requiredNotFeature.length() > 0) {
382          printf(" requiredNotFeature='%s'", requiredNotFeature.string());
383     }
384     printf("\n");
385 
386     if (optional) {
387         printf("optional-permission: name='%s'",
388                 ResTable::normalizeForOutput(name.string()).string());
389         if (maxSdkVersion != -1) {
390             printf(" maxSdkVersion='%d'", maxSdkVersion);
391         }
392         printf("\n");
393     }
394 }
395 
printUsesPermissionSdk23(const String8 & name,int maxSdkVersion=-1)396 static void printUsesPermissionSdk23(const String8& name, int maxSdkVersion=-1) {
397     printf("uses-permission-sdk-23: ");
398 
399     printf("name='%s'", ResTable::normalizeForOutput(name.string()).string());
400     if (maxSdkVersion != -1) {
401         printf(" maxSdkVersion='%d'", maxSdkVersion);
402     }
403     printf("\n");
404 }
405 
printUsesImpliedPermission(const String8 & name,const String8 & reason,const int32_t maxSdkVersion=-1)406 static void printUsesImpliedPermission(const String8& name, const String8& reason,
407         const int32_t maxSdkVersion = -1) {
408     printf("uses-implied-permission: name='%s'",
409             ResTable::normalizeForOutput(name.string()).string());
410     if (maxSdkVersion != -1) {
411         printf(" maxSdkVersion='%d'", maxSdkVersion);
412     }
413     printf(" reason='%s'\n", ResTable::normalizeForOutput(reason.string()).string());
414 }
415 
getNfcAidCategories(AssetManager & assets,const String8 & xmlPath,bool offHost,String8 * outError=NULL)416 Vector<String8> getNfcAidCategories(AssetManager& assets, const String8& xmlPath, bool offHost,
417         String8 *outError = NULL)
418 {
419     Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
420     if (aidAsset == NULL) {
421         if (outError != NULL) *outError = "xml resource does not exist";
422         return Vector<String8>();
423     }
424 
425     const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
426 
427     bool withinApduService = false;
428     Vector<String8> categories;
429 
430     String8 error;
431     ResXMLTree tree;
432     tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
433 
434     size_t len;
435     int depth = 0;
436     ResXMLTree::event_code_t code;
437     while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
438         if (code == ResXMLTree::END_TAG) {
439             depth--;
440             const char16_t* ctag16 = tree.getElementName(&len);
441             if (ctag16 == NULL) {
442                 *outError = "failed to get XML element name (bad string pool)";
443                 return Vector<String8>();
444             }
445             String8 tag(ctag16);
446 
447             if (depth == 0 && tag == serviceTagName) {
448                 withinApduService = false;
449             }
450 
451         } else if (code == ResXMLTree::START_TAG) {
452             depth++;
453             const char16_t* ctag16 = tree.getElementName(&len);
454             if (ctag16 == NULL) {
455                 *outError = "failed to get XML element name (bad string pool)";
456                 return Vector<String8>();
457             }
458             String8 tag(ctag16);
459 
460             if (depth == 1) {
461                 if (tag == serviceTagName) {
462                     withinApduService = true;
463                 }
464             } else if (depth == 2 && withinApduService) {
465                 if (tag == "aid-group") {
466                     String8 category = AaptXml::getAttribute(tree, CATEGORY_ATTR, &error);
467                     if (error != "") {
468                         if (outError != NULL) *outError = error;
469                         return Vector<String8>();
470                     }
471 
472                     categories.add(category);
473                 }
474             }
475         }
476     }
477     aidAsset->close();
478     return categories;
479 }
480 
printComponentPresence(const char * componentName)481 static void printComponentPresence(const char* componentName) {
482     printf("provides-component:'%s'\n", componentName);
483 }
484 
485 /**
486  * Represents a feature that has been automatically added due to
487  * a pre-requisite or some other reason.
488  */
489 struct ImpliedFeature {
ImpliedFeatureImpliedFeature490     ImpliedFeature() : impliedBySdk23(false) {}
ImpliedFeatureImpliedFeature491     ImpliedFeature(const String8& n, bool sdk23) : name(n), impliedBySdk23(sdk23) {}
492 
493     /**
494      * Name of the implied feature.
495      */
496     String8 name;
497 
498     /**
499      * Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)?
500      */
501     bool impliedBySdk23;
502 
503     /**
504      * List of human-readable reasons for why this feature was implied.
505      */
506     SortedVector<String8> reasons;
507 };
508 
509 struct Feature {
FeatureFeature510     Feature() : required(false), version(-1) {}
FeatureFeature511     explicit Feature(bool required, int32_t version = -1) : required(required), version(version) {}
512 
513     /**
514      * Whether the feature is required.
515      */
516     bool required;
517 
518     /**
519      * What version of the feature is requested.
520      */
521     int32_t version;
522 };
523 
524 /**
525  * Represents a <feature-group> tag in the AndroidManifest.xml
526  */
527 struct FeatureGroup {
FeatureGroupFeatureGroup528     FeatureGroup() : openGLESVersion(-1) {}
529 
530     /**
531      * Human readable label
532      */
533     String8 label;
534 
535     /**
536      * Explicit features defined in the group
537      */
538     KeyedVector<String8, Feature> features;
539 
540     /**
541      * OpenGL ES version required
542      */
543     int openGLESVersion;
544 };
545 
hasFeature(const char * name,const FeatureGroup & grp,const KeyedVector<String8,ImpliedFeature> & implied)546 static bool hasFeature(const char* name, const FeatureGroup& grp,
547                        const KeyedVector<String8, ImpliedFeature>& implied) {
548     String8 name8(name);
549     ssize_t idx = grp.features.indexOfKey(name8);
550     if (idx < 0) {
551         idx = implied.indexOfKey(name8);
552     }
553     return idx >= 0;
554 }
555 
addImpliedFeature(KeyedVector<String8,ImpliedFeature> * impliedFeatures,const char * name,const String8 & reason,bool sdk23)556 static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
557                               const char* name, const String8& reason, bool sdk23) {
558     String8 name8(name);
559     ssize_t idx = impliedFeatures->indexOfKey(name8);
560     if (idx < 0) {
561         idx = impliedFeatures->add(name8, ImpliedFeature(name8, sdk23));
562     }
563 
564     ImpliedFeature* feature = &impliedFeatures->editValueAt(idx);
565 
566     // A non-sdk 23 implied feature takes precedence.
567     if (feature->impliedBySdk23 && !sdk23) {
568         feature->impliedBySdk23 = false;
569     }
570     feature->reasons.add(reason);
571 }
572 
printFeatureGroupImpl(const FeatureGroup & grp,const KeyedVector<String8,ImpliedFeature> * impliedFeatures)573 static void printFeatureGroupImpl(const FeatureGroup& grp,
574                                   const KeyedVector<String8, ImpliedFeature>* impliedFeatures) {
575     printf("feature-group: label='%s'\n", grp.label.string());
576 
577     if (grp.openGLESVersion > 0) {
578         printf("  uses-gl-es: '0x%x'\n", grp.openGLESVersion);
579     }
580 
581     const size_t numFeatures = grp.features.size();
582     for (size_t i = 0; i < numFeatures; i++) {
583         const Feature& feature = grp.features[i];
584         const bool required = feature.required;
585         const int32_t version = feature.version;
586 
587         const String8& featureName = grp.features.keyAt(i);
588         printf("  uses-feature%s: name='%s'", (required ? "" : "-not-required"),
589                 ResTable::normalizeForOutput(featureName.string()).string());
590 
591         if (version > 0) {
592             printf(" version='%d'", version);
593         }
594         printf("\n");
595     }
596 
597     const size_t numImpliedFeatures =
598         (impliedFeatures != NULL) ? impliedFeatures->size() : 0;
599     for (size_t i = 0; i < numImpliedFeatures; i++) {
600         const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i);
601         if (grp.features.indexOfKey(impliedFeature.name) >= 0) {
602             // The feature is explicitly set, no need to use implied
603             // definition.
604             continue;
605         }
606 
607         String8 printableFeatureName(ResTable::normalizeForOutput(
608                     impliedFeature.name.string()));
609         const char* sdk23Suffix = impliedFeature.impliedBySdk23 ? "-sdk-23" : "";
610 
611         printf("  uses-feature%s: name='%s'\n", sdk23Suffix, printableFeatureName.string());
612         printf("  uses-implied-feature%s: name='%s' reason='", sdk23Suffix,
613                printableFeatureName.string());
614         const size_t numReasons = impliedFeature.reasons.size();
615         for (size_t j = 0; j < numReasons; j++) {
616             printf("%s", impliedFeature.reasons[j].string());
617             if (j + 2 < numReasons) {
618                 printf(", ");
619             } else if (j + 1 < numReasons) {
620                 printf(", and ");
621             }
622         }
623         printf("'\n");
624     }
625 }
626 
printFeatureGroup(const FeatureGroup & grp)627 static void printFeatureGroup(const FeatureGroup& grp) {
628     printFeatureGroupImpl(grp, NULL);
629 }
630 
printDefaultFeatureGroup(const FeatureGroup & grp,const KeyedVector<String8,ImpliedFeature> & impliedFeatures)631 static void printDefaultFeatureGroup(const FeatureGroup& grp,
632                                      const KeyedVector<String8, ImpliedFeature>& impliedFeatures) {
633     printFeatureGroupImpl(grp, &impliedFeatures);
634 }
635 
addParentFeatures(FeatureGroup * grp,const String8 & name)636 static void addParentFeatures(FeatureGroup* grp, const String8& name) {
637     if (name == "android.hardware.camera.autofocus" ||
638             name == "android.hardware.camera.flash") {
639         grp->features.add(String8("android.hardware.camera"), Feature(true));
640     } else if (name == "android.hardware.location.gps" ||
641             name == "android.hardware.location.network") {
642         grp->features.add(String8("android.hardware.location"), Feature(true));
643     } else if (name == "android.hardware.faketouch.multitouch") {
644         grp->features.add(String8("android.hardware.faketouch"), Feature(true));
645     } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
646             name == "android.hardware.faketouch.multitouch.jazzhands") {
647         grp->features.add(String8("android.hardware.faketouch.multitouch"), Feature(true));
648         grp->features.add(String8("android.hardware.faketouch"), Feature(true));
649     } else if (name == "android.hardware.touchscreen.multitouch") {
650         grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
651     } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
652             name == "android.hardware.touchscreen.multitouch.jazzhands") {
653         grp->features.add(String8("android.hardware.touchscreen.multitouch"), Feature(true));
654         grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
655     } else if (name == "android.hardware.opengles.aep") {
656         const int openGLESVersion31 = 0x00030001;
657         if (openGLESVersion31 > grp->openGLESVersion) {
658             grp->openGLESVersion = openGLESVersion31;
659         }
660     }
661 }
662 
addImpliedFeaturesForPermission(const int targetSdk,const String8 & name,KeyedVector<String8,ImpliedFeature> * impliedFeatures,bool impliedBySdk23Permission)663 static void addImpliedFeaturesForPermission(const int targetSdk, const String8& name,
664                                             KeyedVector<String8, ImpliedFeature>* impliedFeatures,
665                                             bool impliedBySdk23Permission) {
666     if (name == "android.permission.CAMERA") {
667         addImpliedFeature(impliedFeatures, "android.hardware.camera",
668                           String8::format("requested %s permission", name.string()),
669                           impliedBySdk23Permission);
670     } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
671         if (targetSdk < SDK_LOLLIPOP) {
672             addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
673                               String8::format("requested %s permission", name.string()),
674                               impliedBySdk23Permission);
675             addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
676                               String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
677                               impliedBySdk23Permission);
678         }
679         addImpliedFeature(impliedFeatures, "android.hardware.location",
680                 String8::format("requested %s permission", name.string()),
681                 impliedBySdk23Permission);
682     } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
683         if (targetSdk < SDK_LOLLIPOP) {
684             addImpliedFeature(impliedFeatures, "android.hardware.location.network",
685                               String8::format("requested %s permission", name.string()),
686                               impliedBySdk23Permission);
687             addImpliedFeature(impliedFeatures, "android.hardware.location.network",
688                               String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
689                               impliedBySdk23Permission);
690         }
691         addImpliedFeature(impliedFeatures, "android.hardware.location",
692                           String8::format("requested %s permission", name.string()),
693                           impliedBySdk23Permission);
694     } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
695                name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
696                name == "android.permission.INSTALL_LOCATION_PROVIDER") {
697         addImpliedFeature(impliedFeatures, "android.hardware.location",
698                           String8::format("requested %s permission", name.string()),
699                           impliedBySdk23Permission);
700     } else if (name == "android.permission.BLUETOOTH" ||
701                name == "android.permission.BLUETOOTH_ADMIN") {
702         if (targetSdk > SDK_DONUT) {
703             addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
704                               String8::format("requested %s permission", name.string()),
705                               impliedBySdk23Permission);
706             addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
707                               String8::format("targetSdkVersion > %d", SDK_DONUT),
708                               impliedBySdk23Permission);
709         }
710     } else if (name == "android.permission.RECORD_AUDIO") {
711         addImpliedFeature(impliedFeatures, "android.hardware.microphone",
712                           String8::format("requested %s permission", name.string()),
713                           impliedBySdk23Permission);
714     } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
715                name == "android.permission.CHANGE_WIFI_STATE" ||
716                name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
717         addImpliedFeature(impliedFeatures, "android.hardware.wifi",
718                           String8::format("requested %s permission", name.string()),
719                           impliedBySdk23Permission);
720     } else if (name == "android.permission.CALL_PHONE" ||
721                name == "android.permission.CALL_PRIVILEGED" ||
722                name == "android.permission.MODIFY_PHONE_STATE" ||
723                name == "android.permission.PROCESS_OUTGOING_CALLS" ||
724                name == "android.permission.READ_SMS" ||
725                name == "android.permission.RECEIVE_SMS" ||
726                name == "android.permission.RECEIVE_MMS" ||
727                name == "android.permission.RECEIVE_WAP_PUSH" ||
728                name == "android.permission.SEND_SMS" ||
729                name == "android.permission.WRITE_APN_SETTINGS" ||
730                name == "android.permission.WRITE_SMS") {
731         addImpliedFeature(impliedFeatures, "android.hardware.telephony",
732                           String8("requested a telephony permission"),
733                           impliedBySdk23Permission);
734     }
735 }
736 
737 /*
738  * Handle the "dump" command, to extract select data from an archive.
739  */
740 extern char CONSOLE_DATA[2925]; // see EOF
doDump(Bundle * bundle)741 int doDump(Bundle* bundle)
742 {
743     status_t result = UNKNOWN_ERROR;
744 
745     if (bundle->getFileSpecCount() < 1) {
746         fprintf(stderr, "ERROR: no dump option specified\n");
747         return 1;
748     }
749 
750     if (bundle->getFileSpecCount() < 2) {
751         fprintf(stderr, "ERROR: no dump file specified\n");
752         return 1;
753     }
754 
755     const char* option = bundle->getFileSpecEntry(0);
756     const char* filename = bundle->getFileSpecEntry(1);
757 
758     AssetManager assets;
759     int32_t assetsCookie;
760 
761     // Add any dependencies passed in.
762     for (size_t i = 0; i < bundle->getPackageIncludes().size(); i++) {
763       const String8& assetPath = bundle->getPackageIncludes()[i];
764       if (!assets.addAssetPath(assetPath, NULL)) {
765         fprintf(stderr, "ERROR: included asset path %s could not be loaded\n", assetPath.string());
766         return 1;
767       }
768     }
769 
770     if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
771         fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
772         return 1;
773     }
774 
775     // Make a dummy config for retrieving resources...  we need to supply
776     // non-default values for some configs so that we can retrieve resources
777     // in the app that don't have a default.  The most important of these is
778     // the API version because key resources like icons will have an implicit
779     // version if they are using newer config types like density.
780     ResTable_config config;
781     memset(&config, 0, sizeof(ResTable_config));
782     config.language[0] = 'e';
783     config.language[1] = 'n';
784     config.country[0] = 'U';
785     config.country[1] = 'S';
786     config.orientation = ResTable_config::ORIENTATION_PORT;
787     config.density = ResTable_config::DENSITY_MEDIUM;
788     config.sdkVersion = 10000; // Very high.
789     config.screenWidthDp = 320;
790     config.screenHeightDp = 480;
791     config.smallestScreenWidthDp = 320;
792     config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL;
793     assets.setConfiguration(config);
794 
795     const ResTable& res = assets.getResources(false);
796     if (res.getError() != NO_ERROR) {
797         fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
798         return 1;
799     }
800 
801     // Source for AndroidManifest.xml
802     const String8 manifestFile("AndroidManifest.xml");
803 
804     // The dynamicRefTable can be null if there are no resources for this asset cookie.
805     // This fine.
806     const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie);
807 
808     Asset* asset = NULL;
809 
810     if (strcmp("resources", option) == 0) {
811 #ifndef __ANDROID__
812         res.print(bundle->getValues());
813 #endif
814 
815     } else if (strcmp("strings", option) == 0) {
816         const ResStringPool* pool = res.getTableStringBlock(0);
817         printStringPool(pool);
818 
819     } else if (strcmp("xmltree", option) == 0) {
820         if (bundle->getFileSpecCount() < 3) {
821             fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
822             goto bail;
823         }
824 
825         for (int i=2; i<bundle->getFileSpecCount(); i++) {
826             const char* resname = bundle->getFileSpecEntry(i);
827             ResXMLTree tree(dynamicRefTable);
828             asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
829             if (asset == NULL) {
830                 fprintf(stderr, "ERROR: dump failed because resource %s not found\n", resname);
831                 goto bail;
832             }
833 
834             if (tree.setTo(asset->getBuffer(true),
835                            asset->getLength()) != NO_ERROR) {
836                 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
837                 goto bail;
838             }
839             tree.restart();
840             printXMLBlock(&tree);
841             tree.uninit();
842             delete asset;
843             asset = NULL;
844         }
845 
846     } else if (strcmp("xmlstrings", option) == 0) {
847         if (bundle->getFileSpecCount() < 3) {
848             fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
849             goto bail;
850         }
851 
852         for (int i=2; i<bundle->getFileSpecCount(); i++) {
853             const char* resname = bundle->getFileSpecEntry(i);
854             asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
855             if (asset == NULL) {
856                 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
857                 goto bail;
858             }
859 
860             ResXMLTree tree(dynamicRefTable);
861             if (tree.setTo(asset->getBuffer(true),
862                            asset->getLength()) != NO_ERROR) {
863                 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
864                 goto bail;
865             }
866             printStringPool(&tree.getStrings());
867             delete asset;
868             asset = NULL;
869         }
870 
871     } else {
872         asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER);
873         if (asset == NULL) {
874             fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
875             goto bail;
876         }
877 
878         ResXMLTree tree(dynamicRefTable);
879         if (tree.setTo(asset->getBuffer(true),
880                        asset->getLength()) != NO_ERROR) {
881             fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
882             goto bail;
883         }
884         tree.restart();
885 
886         if (strcmp("permissions", option) == 0) {
887             size_t len;
888             ResXMLTree::event_code_t code;
889             int depth = 0;
890             while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
891                     code != ResXMLTree::BAD_DOCUMENT) {
892                 if (code == ResXMLTree::END_TAG) {
893                     depth--;
894                     continue;
895                 }
896                 if (code != ResXMLTree::START_TAG) {
897                     continue;
898                 }
899                 depth++;
900                 const char16_t* ctag16 = tree.getElementName(&len);
901                 if (ctag16 == NULL) {
902                     SourcePos(manifestFile, tree.getLineNumber()).error(
903                             "ERROR: failed to get XML element name (bad string pool)");
904                     goto bail;
905                 }
906                 String8 tag(ctag16);
907                 //printf("Depth %d tag %s\n", depth, tag.string());
908                 if (depth == 1) {
909                     if (tag != "manifest") {
910                         SourcePos(manifestFile, tree.getLineNumber()).error(
911                                 "ERROR: manifest does not start with <manifest> tag");
912                         goto bail;
913                     }
914                     String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
915                     printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
916                 } else if (depth == 2) {
917                     if (tag == "permission") {
918                         String8 error;
919                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
920                         if (error != "") {
921                             SourcePos(manifestFile, tree.getLineNumber()).error(
922                                     "ERROR getting 'android:name': %s", error.string());
923                             goto bail;
924                         }
925 
926                         if (name == "") {
927                             SourcePos(manifestFile, tree.getLineNumber()).error(
928                                     "ERROR: missing 'android:name' for permission");
929                             goto bail;
930                         }
931                         printf("permission: %s\n",
932                                 ResTable::normalizeForOutput(name.string()).string());
933                     } else if (tag == "uses-permission") {
934                         String8 error;
935                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
936                         if (error != "") {
937                             SourcePos(manifestFile, tree.getLineNumber()).error(
938                                     "ERROR getting 'android:name' attribute: %s", error.string());
939                             goto bail;
940                         }
941 
942                         if (name == "") {
943                             SourcePos(manifestFile, tree.getLineNumber()).error(
944                                     "ERROR: missing 'android:name' for uses-permission");
945                             goto bail;
946                         }
947                         printUsesPermission(name,
948                                 AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
949                                 AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
950                     } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
951                         String8 error;
952                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
953                         if (error != "") {
954                             SourcePos(manifestFile, tree.getLineNumber()).error(
955                                     "ERROR getting 'android:name' attribute: %s", error.string());
956                             goto bail;
957                         }
958 
959                         if (name == "") {
960                             SourcePos(manifestFile, tree.getLineNumber()).error(
961                                     "ERROR: missing 'android:name' for uses-permission-sdk-23");
962                             goto bail;
963                         }
964                         printUsesPermissionSdk23(
965                                 name,
966                                 AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
967                     }
968                 }
969             }
970         } else if (strcmp("badging", option) == 0) {
971             Vector<String8> locales;
972             res.getLocales(&locales);
973 
974             Vector<ResTable_config> configs;
975             res.getConfigurations(&configs);
976             SortedVector<int> densities;
977             const size_t NC = configs.size();
978             for (size_t i=0; i<NC; i++) {
979                 int dens = configs[i].density;
980                 if (dens == 0) {
981                     dens = 160;
982                 }
983                 densities.add(dens);
984             }
985 
986             size_t len;
987             ResXMLTree::event_code_t code;
988             int depth = 0;
989             String8 error;
990             bool withinActivity = false;
991             bool isMainActivity = false;
992             bool isLauncherActivity = false;
993             bool isLeanbackLauncherActivity = false;
994             bool isSearchable = false;
995             bool withinApplication = false;
996             bool withinSupportsInput = false;
997             bool withinFeatureGroup = false;
998             bool withinReceiver = false;
999             bool withinService = false;
1000             bool withinProvider = false;
1001             bool withinIntentFilter = false;
1002             bool hasMainActivity = false;
1003             bool hasOtherActivities = false;
1004             bool hasOtherReceivers = false;
1005             bool hasOtherServices = false;
1006             bool hasIntentFilter = false;
1007 
1008             bool hasWallpaperService = false;
1009             bool hasImeService = false;
1010             bool hasAccessibilityService = false;
1011             bool hasPrintService = false;
1012             bool hasWidgetReceivers = false;
1013             bool hasDeviceAdminReceiver = false;
1014             bool hasPaymentService = false;
1015             bool hasDocumentsProvider = false;
1016             bool hasCameraActivity = false;
1017             bool hasCameraSecureActivity = false;
1018             bool hasLauncher = false;
1019             bool hasNotificationListenerService = false;
1020             bool hasDreamService = false;
1021 
1022             bool actMainActivity = false;
1023             bool actWidgetReceivers = false;
1024             bool actDeviceAdminEnabled = false;
1025             bool actImeService = false;
1026             bool actWallpaperService = false;
1027             bool actAccessibilityService = false;
1028             bool actPrintService = false;
1029             bool actHostApduService = false;
1030             bool actOffHostApduService = false;
1031             bool actDocumentsProvider = false;
1032             bool actNotificationListenerService = false;
1033             bool actDreamService = false;
1034             bool actCamera = false;
1035             bool actCameraSecure = false;
1036             bool catLauncher = false;
1037             bool hasMetaHostPaymentCategory = false;
1038             bool hasMetaOffHostPaymentCategory = false;
1039 
1040             // These permissions are required by services implementing services
1041             // the system binds to (IME, Accessibility, PrintServices, etc.)
1042             bool hasBindDeviceAdminPermission = false;
1043             bool hasBindInputMethodPermission = false;
1044             bool hasBindAccessibilityServicePermission = false;
1045             bool hasBindPrintServicePermission = false;
1046             bool hasBindNfcServicePermission = false;
1047             bool hasRequiredSafAttributes = false;
1048             bool hasBindNotificationListenerServicePermission = false;
1049             bool hasBindDreamServicePermission = false;
1050 
1051             // These two implement the implicit permissions that are granted
1052             // to pre-1.6 applications.
1053             bool hasWriteExternalStoragePermission = false;
1054             int32_t writeExternalStoragePermissionMaxSdkVersion = -1;
1055             bool hasReadPhoneStatePermission = false;
1056 
1057             // If an app requests write storage, they will also get read storage.
1058             bool hasReadExternalStoragePermission = false;
1059 
1060             // Implement transition to read and write call log.
1061             bool hasReadContactsPermission = false;
1062             bool hasWriteContactsPermission = false;
1063             bool hasReadCallLogPermission = false;
1064             bool hasWriteCallLogPermission = false;
1065 
1066             // If an app declares itself as multiArch, we report the
1067             // native libraries differently.
1068             bool hasMultiArch = false;
1069 
1070             // This next group of variables is used to implement a group of
1071             // backward-compatibility heuristics necessitated by the addition of
1072             // some new uses-feature constants in 2.1 and 2.2. In most cases, the
1073             // heuristic is "if an app requests a permission but doesn't explicitly
1074             // request the corresponding <uses-feature>, presume it's there anyway".
1075 
1076             // 2.2 also added some other features that apps can request, but that
1077             // have no corresponding permission, so we cannot implement any
1078             // back-compatibility heuristic for them. The below are thus unnecessary
1079             // (but are retained here for documentary purposes.)
1080             //bool specCompassFeature = false;
1081             //bool specAccelerometerFeature = false;
1082             //bool specProximityFeature = false;
1083             //bool specAmbientLightFeature = false;
1084             //bool specLiveWallpaperFeature = false;
1085 
1086             int targetSdk = 0;
1087             int smallScreen = 1;
1088             int normalScreen = 1;
1089             int largeScreen = 1;
1090             int xlargeScreen = 1;
1091             int anyDensity = 1;
1092             int requiresSmallestWidthDp = 0;
1093             int compatibleWidthLimitDp = 0;
1094             int largestWidthLimitDp = 0;
1095             String8 pkg;
1096             String8 activityName;
1097             String8 activityLabel;
1098             String8 activityIcon;
1099             String8 activityBanner;
1100             String8 receiverName;
1101             String8 serviceName;
1102             Vector<String8> supportedInput;
1103 
1104             FeatureGroup commonFeatures;
1105             Vector<FeatureGroup> featureGroups;
1106             KeyedVector<String8, ImpliedFeature> impliedFeatures;
1107 
1108             while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
1109                     code != ResXMLTree::BAD_DOCUMENT) {
1110                 if (code == ResXMLTree::END_TAG) {
1111                     depth--;
1112                     if (depth < 2) {
1113                         if (withinSupportsInput && !supportedInput.isEmpty()) {
1114                             printf("supports-input: '");
1115                             const size_t N = supportedInput.size();
1116                             for (size_t i=0; i<N; i++) {
1117                                 printf("%s", ResTable::normalizeForOutput(
1118                                         supportedInput[i].string()).string());
1119                                 if (i != N - 1) {
1120                                     printf("' '");
1121                                 } else {
1122                                     printf("'\n");
1123                                 }
1124                             }
1125                             supportedInput.clear();
1126                         }
1127                         withinApplication = false;
1128                         withinSupportsInput = false;
1129                         withinFeatureGroup = false;
1130                     } else if (depth < 3) {
1131                         if (withinActivity && isMainActivity) {
1132                             String8 aName(getComponentName(pkg, activityName));
1133                             if (isLauncherActivity) {
1134                                 printf("launchable-activity:");
1135                                 if (aName.length() > 0) {
1136                                     printf(" name='%s' ",
1137                                             ResTable::normalizeForOutput(aName.string()).string());
1138                                 }
1139                                 printf(" label='%s' icon='%s'\n",
1140                                        ResTable::normalizeForOutput(activityLabel.string())
1141                                                 .string(),
1142                                        ResTable::normalizeForOutput(activityIcon.string())
1143                                                 .string());
1144                             }
1145                             if (isLeanbackLauncherActivity) {
1146                                 printf("leanback-launchable-activity:");
1147                                 if (aName.length() > 0) {
1148                                     printf(" name='%s' ",
1149                                             ResTable::normalizeForOutput(aName.string()).string());
1150                                 }
1151                                 printf(" label='%s' icon='%s' banner='%s'\n",
1152                                        ResTable::normalizeForOutput(activityLabel.string())
1153                                                 .string(),
1154                                        ResTable::normalizeForOutput(activityIcon.string())
1155                                                 .string(),
1156                                        ResTable::normalizeForOutput(activityBanner.string())
1157                                                 .string());
1158                             }
1159                         }
1160                         if (!hasIntentFilter) {
1161                             hasOtherActivities |= withinActivity;
1162                             hasOtherReceivers |= withinReceiver;
1163                             hasOtherServices |= withinService;
1164                         } else {
1165                             if (withinService) {
1166                                 hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
1167                                         hasBindNfcServicePermission);
1168                                 hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
1169                                         hasBindNfcServicePermission);
1170                             }
1171                         }
1172                         withinActivity = false;
1173                         withinService = false;
1174                         withinReceiver = false;
1175                         withinProvider = false;
1176                         hasIntentFilter = false;
1177                         isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false;
1178                     } else if (depth < 4) {
1179                         if (withinIntentFilter) {
1180                             if (withinActivity) {
1181                                 hasMainActivity |= actMainActivity;
1182                                 hasLauncher |= catLauncher;
1183                                 hasCameraActivity |= actCamera;
1184                                 hasCameraSecureActivity |= actCameraSecure;
1185                                 hasOtherActivities |=
1186                                         !actMainActivity && !actCamera && !actCameraSecure;
1187                             } else if (withinReceiver) {
1188                                 hasWidgetReceivers |= actWidgetReceivers;
1189                                 hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
1190                                         hasBindDeviceAdminPermission);
1191                                 hasOtherReceivers |=
1192                                         (!actWidgetReceivers && !actDeviceAdminEnabled);
1193                             } else if (withinService) {
1194                                 hasImeService |= actImeService;
1195                                 hasWallpaperService |= actWallpaperService;
1196                                 hasAccessibilityService |= (actAccessibilityService &&
1197                                         hasBindAccessibilityServicePermission);
1198                                 hasPrintService |=
1199                                         (actPrintService && hasBindPrintServicePermission);
1200                                 hasNotificationListenerService |= actNotificationListenerService &&
1201                                         hasBindNotificationListenerServicePermission;
1202                                 hasDreamService |= actDreamService && hasBindDreamServicePermission;
1203                                 hasOtherServices |= (!actImeService && !actWallpaperService &&
1204                                         !actAccessibilityService && !actPrintService &&
1205                                         !actHostApduService && !actOffHostApduService &&
1206                                         !actNotificationListenerService);
1207                             } else if (withinProvider) {
1208                                 hasDocumentsProvider |=
1209                                         actDocumentsProvider && hasRequiredSafAttributes;
1210                             }
1211                         }
1212                         withinIntentFilter = false;
1213                     }
1214                     continue;
1215                 }
1216                 if (code != ResXMLTree::START_TAG) {
1217                     continue;
1218                 }
1219                 depth++;
1220 
1221                 const char16_t* ctag16 = tree.getElementName(&len);
1222                 if (ctag16 == NULL) {
1223                     SourcePos(manifestFile, tree.getLineNumber()).error(
1224                             "ERROR: failed to get XML element name (bad string pool)");
1225                     goto bail;
1226                 }
1227                 String8 tag(ctag16);
1228                 //printf("Depth %d,  %s\n", depth, tag.string());
1229                 if (depth == 1) {
1230                     if (tag != "manifest") {
1231                         SourcePos(manifestFile, tree.getLineNumber()).error(
1232                                 "ERROR: manifest does not start with <manifest> tag");
1233                         goto bail;
1234                     }
1235                     pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
1236                     printf("package: name='%s' ",
1237                             ResTable::normalizeForOutput(pkg.string()).string());
1238                     int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR,
1239                             &error);
1240                     if (error != "") {
1241                         SourcePos(manifestFile, tree.getLineNumber()).error(
1242                                 "ERROR getting 'android:versionCode' attribute: %s",
1243                                 error.string());
1244                         goto bail;
1245                     }
1246                     if (versionCode > 0) {
1247                         printf("versionCode='%d' ", versionCode);
1248                     } else {
1249                         printf("versionCode='' ");
1250                     }
1251                     String8 versionName = AaptXml::getResolvedAttribute(res, tree,
1252                             VERSION_NAME_ATTR, &error);
1253                     if (error != "") {
1254                         SourcePos(manifestFile, tree.getLineNumber()).error(
1255                                 "ERROR getting 'android:versionName' attribute: %s",
1256                                 error.string());
1257                         goto bail;
1258                     }
1259                     printf("versionName='%s'",
1260                             ResTable::normalizeForOutput(versionName.string()).string());
1261 
1262                     String8 splitName = AaptXml::getAttribute(tree, NULL, "split");
1263                     if (!splitName.isEmpty()) {
1264                         printf(" split='%s'", ResTable::normalizeForOutput(
1265                                     splitName.string()).string());
1266                     }
1267 
1268                     String8 platformVersionName = AaptXml::getAttribute(tree, NULL,
1269                             "platformBuildVersionName");
1270                     printf(" platformBuildVersionName='%s'", platformVersionName.string());
1271                     printf("\n");
1272 
1273                     int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree,
1274                             INSTALL_LOCATION_ATTR, &error);
1275                     if (error != "") {
1276                         SourcePos(manifestFile, tree.getLineNumber()).error(
1277                                 "ERROR getting 'android:installLocation' attribute: %s",
1278                                 error.string());
1279                         goto bail;
1280                     }
1281 
1282                     if (installLocation >= 0) {
1283                         printf("install-location:'");
1284                         switch (installLocation) {
1285                             case 0:
1286                                 printf("auto");
1287                                 break;
1288                             case 1:
1289                                 printf("internalOnly");
1290                                 break;
1291                             case 2:
1292                                 printf("preferExternal");
1293                                 break;
1294                             default:
1295                                 fprintf(stderr, "Invalid installLocation %d\n", installLocation);
1296                                 goto bail;
1297                         }
1298                         printf("'\n");
1299                     }
1300                 } else if (depth == 2) {
1301                     withinApplication = false;
1302                     if (tag == "application") {
1303                         withinApplication = true;
1304 
1305                         String8 label;
1306                         const size_t NL = locales.size();
1307                         for (size_t i=0; i<NL; i++) {
1308                             const char* localeStr =  locales[i].string();
1309                             assets.setConfiguration(config, localeStr != NULL ? localeStr : "");
1310                             String8 llabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
1311                                     &error);
1312                             if (llabel != "") {
1313                                 if (localeStr == NULL || strlen(localeStr) == 0) {
1314                                     label = llabel;
1315                                     printf("application-label:'%s'\n",
1316                                             ResTable::normalizeForOutput(llabel.string()).string());
1317                                 } else {
1318                                     if (label == "") {
1319                                         label = llabel;
1320                                     }
1321                                     printf("application-label-%s:'%s'\n", localeStr,
1322                                            ResTable::normalizeForOutput(llabel.string()).string());
1323                                 }
1324                             }
1325                         }
1326 
1327                         ResTable_config tmpConfig = config;
1328                         const size_t ND = densities.size();
1329                         for (size_t i=0; i<ND; i++) {
1330                             tmpConfig.density = densities[i];
1331                             assets.setConfiguration(tmpConfig);
1332                             String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR,
1333                                     &error);
1334                             if (icon != "") {
1335                                 printf("application-icon-%d:'%s'\n", densities[i],
1336                                         ResTable::normalizeForOutput(icon.string()).string());
1337                             }
1338                         }
1339                         assets.setConfiguration(config);
1340 
1341                         String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR, &error);
1342                         if (error != "") {
1343                             SourcePos(manifestFile, tree.getLineNumber()).error(
1344                                     "ERROR getting 'android:icon' attribute: %s", error.string());
1345                             goto bail;
1346                         }
1347                         int32_t testOnly = AaptXml::getIntegerAttribute(tree, TEST_ONLY_ATTR, 0,
1348                                 &error);
1349                         if (error != "") {
1350                             SourcePos(manifestFile, tree.getLineNumber()).error(
1351                                     "ERROR getting 'android:testOnly' attribute: %s",
1352                                     error.string());
1353                             goto bail;
1354                         }
1355 
1356                         String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
1357                                                                        &error);
1358                         if (error != "") {
1359                             SourcePos(manifestFile, tree.getLineNumber()).error(
1360                                     "ERROR getting 'android:banner' attribute: %s", error.string());
1361                             goto bail;
1362                         }
1363                         printf("application: label='%s' ",
1364                                 ResTable::normalizeForOutput(label.string()).string());
1365                         printf("icon='%s'", ResTable::normalizeForOutput(icon.string()).string());
1366                         if (banner != "") {
1367                             printf(" banner='%s'",
1368                                    ResTable::normalizeForOutput(banner.string()).string());
1369                         }
1370                         printf("\n");
1371                         if (testOnly != 0) {
1372                             printf("testOnly='%d'\n", testOnly);
1373                         }
1374 
1375                         int32_t isGame = AaptXml::getResolvedIntegerAttribute(res, tree,
1376                                 ISGAME_ATTR, 0, &error);
1377                         if (error != "") {
1378                             SourcePos(manifestFile, tree.getLineNumber()).error(
1379                                     "ERROR getting 'android:isGame' attribute: %s", error.string());
1380                             goto bail;
1381                         }
1382                         if (isGame != 0) {
1383                             printf("application-isGame\n");
1384                         }
1385 
1386                         int32_t debuggable = AaptXml::getResolvedIntegerAttribute(res, tree,
1387                                 DEBUGGABLE_ATTR, 0, &error);
1388                         if (error != "") {
1389                             SourcePos(manifestFile, tree.getLineNumber()).error(
1390                                     "ERROR getting 'android:debuggable' attribute: %s",
1391                                     error.string());
1392                             goto bail;
1393                         }
1394                         if (debuggable != 0) {
1395                             printf("application-debuggable\n");
1396                         }
1397 
1398                         // We must search by name because the multiArch flag hasn't been API
1399                         // frozen yet.
1400                         int32_t multiArchIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
1401                                 "multiArch");
1402                         if (multiArchIndex >= 0) {
1403                             Res_value value;
1404                             if (tree.getAttributeValue(multiArchIndex, &value) != NO_ERROR) {
1405                                 if (value.dataType >= Res_value::TYPE_FIRST_INT &&
1406                                         value.dataType <= Res_value::TYPE_LAST_INT) {
1407                                     hasMultiArch = value.data;
1408                                 }
1409                             }
1410                         }
1411                     } else if (tag == "uses-sdk") {
1412                         int32_t code = AaptXml::getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR,
1413                                                                     &error);
1414                         if (error != "") {
1415                             error = "";
1416                             String8 name = AaptXml::getResolvedAttribute(res, tree,
1417                                     MIN_SDK_VERSION_ATTR, &error);
1418                             if (error != "") {
1419                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1420                                         "ERROR getting 'android:minSdkVersion' attribute: %s",
1421                                         error.string());
1422                                 goto bail;
1423                             }
1424                             if (name == "Donut") targetSdk = 4;
1425                             printf("sdkVersion:'%s'\n",
1426                                     ResTable::normalizeForOutput(name.string()).string());
1427                         } else if (code != -1) {
1428                             targetSdk = code;
1429                             printf("sdkVersion:'%d'\n", code);
1430                         }
1431                         code = AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR);
1432                         if (code != -1) {
1433                             printf("maxSdkVersion:'%d'\n", code);
1434                         }
1435                         code = AaptXml::getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
1436                         if (error != "") {
1437                             error = "";
1438                             String8 name = AaptXml::getResolvedAttribute(res, tree,
1439                                     TARGET_SDK_VERSION_ATTR, &error);
1440                             if (error != "") {
1441                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1442                                         "ERROR getting 'android:targetSdkVersion' attribute: %s",
1443                                         error.string());
1444                                 goto bail;
1445                             }
1446                             if (name == "Donut" && targetSdk < 4) targetSdk = 4;
1447                             printf("targetSdkVersion:'%s'\n",
1448                                     ResTable::normalizeForOutput(name.string()).string());
1449                         } else if (code != -1) {
1450                             if (targetSdk < code) {
1451                                 targetSdk = code;
1452                             }
1453                             printf("targetSdkVersion:'%d'\n", code);
1454                         }
1455                     } else if (tag == "uses-configuration") {
1456                         int32_t reqTouchScreen = AaptXml::getIntegerAttribute(tree,
1457                                 REQ_TOUCH_SCREEN_ATTR, 0);
1458                         int32_t reqKeyboardType = AaptXml::getIntegerAttribute(tree,
1459                                 REQ_KEYBOARD_TYPE_ATTR, 0);
1460                         int32_t reqHardKeyboard = AaptXml::getIntegerAttribute(tree,
1461                                 REQ_HARD_KEYBOARD_ATTR, 0);
1462                         int32_t reqNavigation = AaptXml::getIntegerAttribute(tree,
1463                                 REQ_NAVIGATION_ATTR, 0);
1464                         int32_t reqFiveWayNav = AaptXml::getIntegerAttribute(tree,
1465                                 REQ_FIVE_WAY_NAV_ATTR, 0);
1466                         printf("uses-configuration:");
1467                         if (reqTouchScreen != 0) {
1468                             printf(" reqTouchScreen='%d'", reqTouchScreen);
1469                         }
1470                         if (reqKeyboardType != 0) {
1471                             printf(" reqKeyboardType='%d'", reqKeyboardType);
1472                         }
1473                         if (reqHardKeyboard != 0) {
1474                             printf(" reqHardKeyboard='%d'", reqHardKeyboard);
1475                         }
1476                         if (reqNavigation != 0) {
1477                             printf(" reqNavigation='%d'", reqNavigation);
1478                         }
1479                         if (reqFiveWayNav != 0) {
1480                             printf(" reqFiveWayNav='%d'", reqFiveWayNav);
1481                         }
1482                         printf("\n");
1483                     } else if (tag == "supports-input") {
1484                         withinSupportsInput = true;
1485                     } else if (tag == "supports-screens") {
1486                         smallScreen = AaptXml::getIntegerAttribute(tree,
1487                                 SMALL_SCREEN_ATTR, 1);
1488                         normalScreen = AaptXml::getIntegerAttribute(tree,
1489                                 NORMAL_SCREEN_ATTR, 1);
1490                         largeScreen = AaptXml::getIntegerAttribute(tree,
1491                                 LARGE_SCREEN_ATTR, 1);
1492                         xlargeScreen = AaptXml::getIntegerAttribute(tree,
1493                                 XLARGE_SCREEN_ATTR, 1);
1494                         anyDensity = AaptXml::getIntegerAttribute(tree,
1495                                 ANY_DENSITY_ATTR, 1);
1496                         requiresSmallestWidthDp = AaptXml::getIntegerAttribute(tree,
1497                                 REQUIRES_SMALLEST_WIDTH_DP_ATTR, 0);
1498                         compatibleWidthLimitDp = AaptXml::getIntegerAttribute(tree,
1499                                 COMPATIBLE_WIDTH_LIMIT_DP_ATTR, 0);
1500                         largestWidthLimitDp = AaptXml::getIntegerAttribute(tree,
1501                                 LARGEST_WIDTH_LIMIT_DP_ATTR, 0);
1502                     } else if (tag == "feature-group") {
1503                         withinFeatureGroup = true;
1504                         FeatureGroup group;
1505                         group.label = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR, &error);
1506                         if (error != "") {
1507                             SourcePos(manifestFile, tree.getLineNumber()).error(
1508                                     "ERROR getting 'android:label' attribute: %s", error.string());
1509                             goto bail;
1510                         }
1511                         featureGroups.add(group);
1512 
1513                     } else if (tag == "uses-feature") {
1514                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1515                         if (name != "" && error == "") {
1516                             const char* androidSchema =
1517                                     "http://schemas.android.com/apk/res/android";
1518 
1519                             int32_t req = AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1,
1520                                                                        &error);
1521                             if (error != "") {
1522                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1523                                         "failed to read attribute 'android:required': %s",
1524                                         error.string());
1525                                 goto bail;
1526                             }
1527 
1528                             int32_t version = AaptXml::getIntegerAttribute(tree, androidSchema,
1529                                                                            "version", 0, &error);
1530                             if (error != "") {
1531                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1532                                         "failed to read attribute 'android:version': %s",
1533                                         error.string());
1534                                 goto bail;
1535                             }
1536 
1537                             commonFeatures.features.add(name, Feature(req != 0, version));
1538                             if (req) {
1539                                 addParentFeatures(&commonFeatures, name);
1540                             }
1541                         } else {
1542                             int vers = AaptXml::getIntegerAttribute(tree,
1543                                     GL_ES_VERSION_ATTR, &error);
1544                             if (error == "") {
1545                                 if (vers > commonFeatures.openGLESVersion) {
1546                                     commonFeatures.openGLESVersion = vers;
1547                                 }
1548                             }
1549                         }
1550                     } else if (tag == "uses-permission") {
1551                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1552                         if (error != "") {
1553                             SourcePos(manifestFile, tree.getLineNumber()).error(
1554                                     "ERROR getting 'android:name' attribute: %s", error.string());
1555                             goto bail;
1556                         }
1557 
1558                         if (name == "") {
1559                             SourcePos(manifestFile, tree.getLineNumber()).error(
1560                                     "ERROR: missing 'android:name' for uses-permission");
1561                             goto bail;
1562                         }
1563 
1564                         addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, false);
1565 
1566                         const int32_t maxSdkVersion =
1567                                 AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, -1);
1568                         const String8 requiredFeature = AaptXml::getAttribute(tree,
1569                                 REQUIRED_FEATURE_ATTR, &error);
1570                         const String8 requiredNotFeature = AaptXml::getAttribute(tree,
1571                                 REQUIRED_NOT_FEATURE_ATTR, &error);
1572 
1573                         if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
1574                             hasWriteExternalStoragePermission = true;
1575                             writeExternalStoragePermissionMaxSdkVersion = maxSdkVersion;
1576                         } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
1577                             hasReadExternalStoragePermission = true;
1578                         } else if (name == "android.permission.READ_PHONE_STATE") {
1579                             hasReadPhoneStatePermission = true;
1580                         } else if (name == "android.permission.READ_CONTACTS") {
1581                             hasReadContactsPermission = true;
1582                         } else if (name == "android.permission.WRITE_CONTACTS") {
1583                             hasWriteContactsPermission = true;
1584                         } else if (name == "android.permission.READ_CALL_LOG") {
1585                             hasReadCallLogPermission = true;
1586                         } else if (name == "android.permission.WRITE_CALL_LOG") {
1587                             hasWriteCallLogPermission = true;
1588                         }
1589 
1590                         printUsesPermission(name,
1591                                 AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
1592                                 maxSdkVersion, requiredFeature, requiredNotFeature);
1593 
1594                     } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
1595                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1596                         if (error != "") {
1597                             SourcePos(manifestFile, tree.getLineNumber()).error(
1598                                     "ERROR getting 'android:name' attribute: %s", error.string());
1599                             goto bail;
1600                         }
1601 
1602                         if (name == "") {
1603                             SourcePos(manifestFile, tree.getLineNumber()).error(
1604                                     "ERROR: missing 'android:name' for uses-permission-sdk-23");
1605                             goto bail;
1606                         }
1607 
1608                         addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, true);
1609 
1610                         printUsesPermissionSdk23(
1611                                 name, AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
1612 
1613                     } else if (tag == "uses-package") {
1614                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1615                         if (name != "" && error == "") {
1616                             printf("uses-package:'%s'\n",
1617                                     ResTable::normalizeForOutput(name.string()).string());
1618                         } else {
1619                             SourcePos(manifestFile, tree.getLineNumber()).error(
1620                                     "ERROR getting 'android:name' attribute: %s", error.string());
1621                             goto bail;
1622                         }
1623                     } else if (tag == "original-package") {
1624                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1625                         if (name != "" && error == "") {
1626                             printf("original-package:'%s'\n",
1627                                     ResTable::normalizeForOutput(name.string()).string());
1628                         } else {
1629                             SourcePos(manifestFile, tree.getLineNumber()).error(
1630                                     "ERROR getting 'android:name' attribute: %s", error.string());
1631                             goto bail;
1632                         }
1633                     } else if (tag == "supports-gl-texture") {
1634                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1635                         if (name != "" && error == "") {
1636                             printf("supports-gl-texture:'%s'\n",
1637                                     ResTable::normalizeForOutput(name.string()).string());
1638                         } else {
1639                             SourcePos(manifestFile, tree.getLineNumber()).error(
1640                                     "ERROR getting 'android:name' attribute: %s", error.string());
1641                             goto bail;
1642                         }
1643                     } else if (tag == "compatible-screens") {
1644                         printCompatibleScreens(tree, &error);
1645                         if (error != "") {
1646                             SourcePos(manifestFile, tree.getLineNumber()).error(
1647                                     "ERROR getting compatible screens: %s", error.string());
1648                             goto bail;
1649                         }
1650                         depth--;
1651                     } else if (tag == "package-verifier") {
1652                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1653                         if (name != "" && error == "") {
1654                             String8 publicKey = AaptXml::getAttribute(tree, PUBLIC_KEY_ATTR,
1655                                                                       &error);
1656                             if (publicKey != "" && error == "") {
1657                                 printf("package-verifier: name='%s' publicKey='%s'\n",
1658                                         ResTable::normalizeForOutput(name.string()).string(),
1659                                         ResTable::normalizeForOutput(publicKey.string()).string());
1660                             }
1661                         }
1662                     }
1663                 } else if (depth == 3) {
1664                     withinActivity = false;
1665                     withinReceiver = false;
1666                     withinService = false;
1667                     withinProvider = false;
1668                     hasIntentFilter = false;
1669                     hasMetaHostPaymentCategory = false;
1670                     hasMetaOffHostPaymentCategory = false;
1671                     hasBindDeviceAdminPermission = false;
1672                     hasBindInputMethodPermission = false;
1673                     hasBindAccessibilityServicePermission = false;
1674                     hasBindPrintServicePermission = false;
1675                     hasBindNfcServicePermission = false;
1676                     hasRequiredSafAttributes = false;
1677                     hasBindNotificationListenerServicePermission = false;
1678                     hasBindDreamServicePermission = false;
1679                     if (withinApplication) {
1680                         if(tag == "activity") {
1681                             withinActivity = true;
1682                             activityName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1683                             if (error != "") {
1684                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1685                                         "ERROR getting 'android:name' attribute: %s",
1686                                         error.string());
1687                                 goto bail;
1688                             }
1689 
1690                             activityLabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
1691                                     &error);
1692                             if (error != "") {
1693                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1694                                         "ERROR getting 'android:label' attribute: %s",
1695                                         error.string());
1696                                 goto bail;
1697                             }
1698 
1699                             activityIcon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR,
1700                                     &error);
1701                             if (error != "") {
1702                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1703                                         "ERROR getting 'android:icon' attribute: %s",
1704                                         error.string());
1705                                 goto bail;
1706                             }
1707 
1708                             activityBanner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
1709                                     &error);
1710                             if (error != "") {
1711                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1712                                         "ERROR getting 'android:banner' attribute: %s",
1713                                         error.string());
1714                                 goto bail;
1715                             }
1716 
1717                             int32_t orien = AaptXml::getResolvedIntegerAttribute(res, tree,
1718                                     SCREEN_ORIENTATION_ATTR, &error);
1719                             if (error == "") {
1720                                 if (orien == 0 || orien == 6 || orien == 8) {
1721                                     // Requests landscape, sensorLandscape, or reverseLandscape.
1722                                     addImpliedFeature(
1723                                             &impliedFeatures, "android.hardware.screen.landscape",
1724                                             String8("one or more activities have specified a "
1725                                                     "landscape orientation"),
1726                                             false);
1727                                 } else if (orien == 1 || orien == 7 || orien == 9) {
1728                                     // Requests portrait, sensorPortrait, or reversePortrait.
1729                                     addImpliedFeature(
1730                                             &impliedFeatures, "android.hardware.screen.portrait",
1731                                             String8("one or more activities have specified a "
1732                                                     "portrait orientation"),
1733                                             false);
1734                                 }
1735                             }
1736                         } else if (tag == "uses-library") {
1737                             String8 libraryName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1738                             if (error != "") {
1739                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1740                                         "ERROR getting 'android:name' attribute for uses-library"
1741                                         " %s", error.string());
1742                                 goto bail;
1743                             }
1744                             int req = AaptXml::getIntegerAttribute(tree,
1745                                     REQUIRED_ATTR, 1);
1746                             printf("uses-library%s:'%s'\n",
1747                                     req ? "" : "-not-required", ResTable::normalizeForOutput(
1748                                             libraryName.string()).string());
1749                         } else if (tag == "receiver") {
1750                             withinReceiver = true;
1751                             receiverName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1752 
1753                             if (error != "") {
1754                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1755                                         "ERROR getting 'android:name' attribute for receiver:"
1756                                         " %s", error.string());
1757                                 goto bail;
1758                             }
1759 
1760                             String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR,
1761                                     &error);
1762                             if (error == "") {
1763                                 if (permission == "android.permission.BIND_DEVICE_ADMIN") {
1764                                     hasBindDeviceAdminPermission = true;
1765                                 }
1766                             } else {
1767                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1768                                         "ERROR getting 'android:permission' attribute for"
1769                                         " receiver '%s': %s",
1770                                         receiverName.string(), error.string());
1771                             }
1772                         } else if (tag == "service") {
1773                             withinService = true;
1774                             serviceName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1775 
1776                             if (error != "") {
1777                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1778                                         "ERROR getting 'android:name' attribute for "
1779                                         "service:%s", error.string());
1780                                 goto bail;
1781                             }
1782 
1783                             String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR,
1784                                     &error);
1785                             if (error == "") {
1786                                 if (permission == "android.permission.BIND_INPUT_METHOD") {
1787                                     hasBindInputMethodPermission = true;
1788                                 } else if (permission ==
1789                                         "android.permission.BIND_ACCESSIBILITY_SERVICE") {
1790                                     hasBindAccessibilityServicePermission = true;
1791                                 } else if (permission ==
1792                                         "android.permission.BIND_PRINT_SERVICE") {
1793                                     hasBindPrintServicePermission = true;
1794                                 } else if (permission ==
1795                                         "android.permission.BIND_NFC_SERVICE") {
1796                                     hasBindNfcServicePermission = true;
1797                                 } else if (permission ==
1798                                         "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
1799                                     hasBindNotificationListenerServicePermission = true;
1800                                 } else if (permission == "android.permission.BIND_DREAM_SERVICE") {
1801                                     hasBindDreamServicePermission = true;
1802                                 }
1803                             } else {
1804                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1805                                         "ERROR getting 'android:permission' attribute for "
1806                                         "service '%s': %s", serviceName.string(), error.string());
1807                             }
1808                         } else if (tag == "provider") {
1809                             withinProvider = true;
1810 
1811                             bool exported = AaptXml::getResolvedIntegerAttribute(res, tree,
1812                                     EXPORTED_ATTR, &error);
1813                             if (error != "") {
1814                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1815                                         "ERROR getting 'android:exported' attribute for provider:"
1816                                         " %s", error.string());
1817                                 goto bail;
1818                             }
1819 
1820                             bool grantUriPermissions = AaptXml::getResolvedIntegerAttribute(
1821                                     res, tree, GRANT_URI_PERMISSIONS_ATTR, &error);
1822                             if (error != "") {
1823                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1824                                         "ERROR getting 'android:grantUriPermissions' attribute for "
1825                                         "provider: %s", error.string());
1826                                 goto bail;
1827                             }
1828 
1829                             String8 permission = AaptXml::getResolvedAttribute(res, tree,
1830                                     PERMISSION_ATTR, &error);
1831                             if (error != "") {
1832                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1833                                         "ERROR getting 'android:permission' attribute for "
1834                                         "provider: %s", error.string());
1835                                 goto bail;
1836                             }
1837 
1838                             hasRequiredSafAttributes |= exported && grantUriPermissions &&
1839                                 permission == "android.permission.MANAGE_DOCUMENTS";
1840 
1841                         } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
1842                             String8 metaDataName = AaptXml::getResolvedAttribute(res, tree,
1843                                     NAME_ATTR, &error);
1844                             if (error != "") {
1845                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1846                                         "ERROR getting 'android:name' attribute for "
1847                                         "meta-data: %s", error.string());
1848                                 goto bail;
1849                             }
1850                             printf("meta-data: name='%s' ",
1851                                     ResTable::normalizeForOutput(metaDataName.string()).string());
1852                             printResolvedResourceAttribute(res, tree, VALUE_ATTR, String8("value"),
1853                                     &error);
1854                             if (error != "") {
1855                                 // Try looking for a RESOURCE_ATTR
1856                                 error = "";
1857                                 printResolvedResourceAttribute(res, tree, RESOURCE_ATTR,
1858                                         String8("resource"), &error);
1859                                 if (error != "") {
1860                                     SourcePos(manifestFile, tree.getLineNumber()).error(
1861                                             "ERROR getting 'android:value' or "
1862                                             "'android:resource' attribute for "
1863                                             "meta-data: %s", error.string());
1864                                     goto bail;
1865                                 }
1866                             }
1867                             printf("\n");
1868                         } else if (withinSupportsInput && tag == "input-type") {
1869                             String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1870                             if (name != "" && error == "") {
1871                                 supportedInput.add(name);
1872                             } else {
1873                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1874                                         "ERROR getting 'android:name' attribute: %s",
1875                                         error.string());
1876                                 goto bail;
1877                             }
1878                         }
1879                     } else if (withinFeatureGroup && tag == "uses-feature") {
1880                         const String8 androidSchema("http://schemas.android.com/apk/res/android");
1881                         FeatureGroup& top = featureGroups.editTop();
1882 
1883                         String8 name = AaptXml::getResolvedAttribute(res, tree, NAME_ATTR, &error);
1884                         if (name != "" && error == "") {
1885                             Feature feature(true);
1886 
1887                             int32_t featureVers = AaptXml::getIntegerAttribute(
1888                                     tree, androidSchema.string(), "version", 0, &error);
1889                             if (error == "") {
1890                                 feature.version = featureVers;
1891                             } else {
1892                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1893                                         "failed to read attribute 'android:version': %s",
1894                                         error.string());
1895                                 goto bail;
1896                             }
1897 
1898                             top.features.add(name, feature);
1899                             addParentFeatures(&top, name);
1900 
1901                         } else {
1902                             int vers = AaptXml::getIntegerAttribute(tree, GL_ES_VERSION_ATTR,
1903                                     &error);
1904                             if (error == "") {
1905                                 if (vers > top.openGLESVersion) {
1906                                     top.openGLESVersion = vers;
1907                                 }
1908                             }
1909                         }
1910                     }
1911                 } else if (depth == 4) {
1912                     if (tag == "intent-filter") {
1913                         hasIntentFilter = true;
1914                         withinIntentFilter = true;
1915                         actMainActivity = false;
1916                         actWidgetReceivers = false;
1917                         actImeService = false;
1918                         actWallpaperService = false;
1919                         actAccessibilityService = false;
1920                         actPrintService = false;
1921                         actDeviceAdminEnabled = false;
1922                         actHostApduService = false;
1923                         actOffHostApduService = false;
1924                         actDocumentsProvider = false;
1925                         actNotificationListenerService = false;
1926                         actDreamService = false;
1927                         actCamera = false;
1928                         actCameraSecure = false;
1929                         catLauncher = false;
1930                     } else if (withinService && tag == "meta-data") {
1931                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1932                         if (error != "") {
1933                             SourcePos(manifestFile, tree.getLineNumber()).error(
1934                                     "ERROR getting 'android:name' attribute for "
1935                                     "meta-data tag in service '%s': %s", serviceName.string(),
1936                                     error.string());
1937                             goto bail;
1938                         }
1939 
1940                         if (name == "android.nfc.cardemulation.host_apdu_service" ||
1941                                 name == "android.nfc.cardemulation.off_host_apdu_service") {
1942                             bool offHost = true;
1943                             if (name == "android.nfc.cardemulation.host_apdu_service") {
1944                                 offHost = false;
1945                             }
1946 
1947                             String8 xmlPath = AaptXml::getResolvedAttribute(res, tree,
1948                                     RESOURCE_ATTR, &error);
1949                             if (error != "") {
1950                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1951                                         "ERROR getting 'android:resource' attribute for "
1952                                         "meta-data tag in service '%s': %s",
1953                                         serviceName.string(), error.string());
1954                                 goto bail;
1955                             }
1956 
1957                             Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
1958                                     offHost, &error);
1959                             if (error != "") {
1960                                 SourcePos(manifestFile, tree.getLineNumber()).error(
1961                                         "ERROR getting AID category for service '%s'",
1962                                         serviceName.string());
1963                                 goto bail;
1964                             }
1965 
1966                             const size_t catLen = categories.size();
1967                             for (size_t i = 0; i < catLen; i++) {
1968                                 bool paymentCategory = (categories[i] == "payment");
1969                                 if (offHost) {
1970                                     hasMetaOffHostPaymentCategory |= paymentCategory;
1971                                 } else {
1972                                     hasMetaHostPaymentCategory |= paymentCategory;
1973                                 }
1974                             }
1975                         }
1976                     }
1977                 } else if ((depth == 5) && withinIntentFilter) {
1978                     String8 action;
1979                     if (tag == "action") {
1980                         action = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1981                         if (error != "") {
1982                             SourcePos(manifestFile, tree.getLineNumber()).error(
1983                                     "ERROR getting 'android:name' attribute: %s", error.string());
1984                             goto bail;
1985                         }
1986 
1987                         if (withinActivity) {
1988                             if (action == "android.intent.action.MAIN") {
1989                                 isMainActivity = true;
1990                                 actMainActivity = true;
1991                             } else if (action == "android.media.action.STILL_IMAGE_CAMERA" ||
1992                                     action == "android.media.action.VIDEO_CAMERA") {
1993                                 actCamera = true;
1994                             } else if (action == "android.media.action.STILL_IMAGE_CAMERA_SECURE") {
1995                                 actCameraSecure = true;
1996                             }
1997                         } else if (withinReceiver) {
1998                             if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
1999                                 actWidgetReceivers = true;
2000                             } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
2001                                 actDeviceAdminEnabled = true;
2002                             }
2003                         } else if (withinService) {
2004                             if (action == "android.view.InputMethod") {
2005                                 actImeService = true;
2006                             } else if (action == "android.service.wallpaper.WallpaperService") {
2007                                 actWallpaperService = true;
2008                             } else if (action ==
2009                                     "android.accessibilityservice.AccessibilityService") {
2010                                 actAccessibilityService = true;
2011                             } else if (action =="android.printservice.PrintService") {
2012                                 actPrintService = true;
2013                             } else if (action ==
2014                                     "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
2015                                 actHostApduService = true;
2016                             } else if (action ==
2017                                     "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
2018                                 actOffHostApduService = true;
2019                             } else if (action ==
2020                                     "android.service.notification.NotificationListenerService") {
2021                                 actNotificationListenerService = true;
2022                             } else if (action == "android.service.dreams.DreamService") {
2023                                 actDreamService = true;
2024                             }
2025                         } else if (withinProvider) {
2026                             if (action == "android.content.action.DOCUMENTS_PROVIDER") {
2027                                 actDocumentsProvider = true;
2028                             }
2029                         }
2030                         if (action == "android.intent.action.SEARCH") {
2031                             isSearchable = true;
2032                         }
2033                     }
2034 
2035                     if (tag == "category") {
2036                         String8 category = AaptXml::getAttribute(tree, NAME_ATTR, &error);
2037                         if (error != "") {
2038                             SourcePos(manifestFile, tree.getLineNumber()).error(
2039                                     "ERROR getting 'name' attribute: %s", error.string());
2040                             goto bail;
2041                         }
2042                         if (withinActivity) {
2043                             if (category == "android.intent.category.LAUNCHER") {
2044                                 isLauncherActivity = true;
2045                             } else if (category == "android.intent.category.LEANBACK_LAUNCHER") {
2046                                 isLeanbackLauncherActivity = true;
2047                             } else if (category == "android.intent.category.HOME") {
2048                                 catLauncher = true;
2049                             }
2050                         }
2051                     }
2052                 }
2053             }
2054 
2055             // Pre-1.6 implicitly granted permission compatibility logic
2056             if (targetSdk < 4) {
2057                 if (!hasWriteExternalStoragePermission) {
2058                     printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
2059                     printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
2060                             String8("targetSdkVersion < 4"));
2061                     hasWriteExternalStoragePermission = true;
2062                 }
2063                 if (!hasReadPhoneStatePermission) {
2064                     printUsesPermission(String8("android.permission.READ_PHONE_STATE"));
2065                     printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"),
2066                             String8("targetSdkVersion < 4"));
2067                 }
2068             }
2069 
2070             // If the application has requested WRITE_EXTERNAL_STORAGE, we will
2071             // force them to always take READ_EXTERNAL_STORAGE as well.  We always
2072             // do this (regardless of target API version) because we can't have
2073             // an app with write permission but not read permission.
2074             if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
2075                 printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
2076                         false /* optional */, writeExternalStoragePermissionMaxSdkVersion);
2077                 printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
2078                         String8("requested WRITE_EXTERNAL_STORAGE"),
2079                         writeExternalStoragePermissionMaxSdkVersion);
2080             }
2081 
2082             // Pre-JellyBean call log permission compatibility.
2083             if (targetSdk < 16) {
2084                 if (!hasReadCallLogPermission && hasReadContactsPermission) {
2085                     printUsesPermission(String8("android.permission.READ_CALL_LOG"));
2086                     printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
2087                             String8("targetSdkVersion < 16 and requested READ_CONTACTS"));
2088                 }
2089                 if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
2090                     printUsesPermission(String8("android.permission.WRITE_CALL_LOG"));
2091                     printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"),
2092                             String8("targetSdkVersion < 16 and requested WRITE_CONTACTS"));
2093                 }
2094             }
2095 
2096             // If the app hasn't declared the touchscreen as a feature requirement (either
2097             // directly or implied, required or not), then the faketouch feature is implied.
2098             if (!hasFeature("android.hardware.touchscreen", commonFeatures, impliedFeatures)) {
2099                 addImpliedFeature(&impliedFeatures, "android.hardware.faketouch",
2100                                   String8("default feature for all apps"), false);
2101             }
2102 
2103             const size_t numFeatureGroups = featureGroups.size();
2104             if (numFeatureGroups == 0) {
2105                 // If no <feature-group> tags were defined, apply auto-implied features.
2106                 printDefaultFeatureGroup(commonFeatures, impliedFeatures);
2107 
2108             } else {
2109                 // <feature-group> tags are defined, so we ignore implied features and
2110                 for (size_t i = 0; i < numFeatureGroups; i++) {
2111                     FeatureGroup& grp = featureGroups.editItemAt(i);
2112 
2113                     if (commonFeatures.openGLESVersion > grp.openGLESVersion) {
2114                         grp.openGLESVersion = commonFeatures.openGLESVersion;
2115                     }
2116 
2117                     // Merge the features defined in the top level (not inside a <feature-group>)
2118                     // with this feature group.
2119                     const size_t numCommonFeatures = commonFeatures.features.size();
2120                     for (size_t j = 0; j < numCommonFeatures; j++) {
2121                         if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) {
2122                             grp.features.add(commonFeatures.features.keyAt(j),
2123                                     commonFeatures.features[j]);
2124                         }
2125                     }
2126 
2127                     if (!grp.features.isEmpty()) {
2128                         printFeatureGroup(grp);
2129                     }
2130                 }
2131             }
2132 
2133 
2134             if (hasWidgetReceivers) {
2135                 printComponentPresence("app-widget");
2136             }
2137             if (hasDeviceAdminReceiver) {
2138                 printComponentPresence("device-admin");
2139             }
2140             if (hasImeService) {
2141                 printComponentPresence("ime");
2142             }
2143             if (hasWallpaperService) {
2144                 printComponentPresence("wallpaper");
2145             }
2146             if (hasAccessibilityService) {
2147                 printComponentPresence("accessibility");
2148             }
2149             if (hasPrintService) {
2150                 printComponentPresence("print-service");
2151             }
2152             if (hasPaymentService) {
2153                 printComponentPresence("payment");
2154             }
2155             if (isSearchable) {
2156                 printComponentPresence("search");
2157             }
2158             if (hasDocumentsProvider) {
2159                 printComponentPresence("document-provider");
2160             }
2161             if (hasLauncher) {
2162                 printComponentPresence("launcher");
2163             }
2164             if (hasNotificationListenerService) {
2165                 printComponentPresence("notification-listener");
2166             }
2167             if (hasDreamService) {
2168                 printComponentPresence("dream");
2169             }
2170             if (hasCameraActivity) {
2171                 printComponentPresence("camera");
2172             }
2173             if (hasCameraSecureActivity) {
2174                 printComponentPresence("camera-secure");
2175             }
2176 
2177             if (hasMainActivity) {
2178                 printf("main\n");
2179             }
2180             if (hasOtherActivities) {
2181                 printf("other-activities\n");
2182             }
2183              if (hasOtherReceivers) {
2184                 printf("other-receivers\n");
2185             }
2186             if (hasOtherServices) {
2187                 printf("other-services\n");
2188             }
2189 
2190             // For modern apps, if screen size buckets haven't been specified
2191             // but the new width ranges have, then infer the buckets from them.
2192             if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
2193                     && requiresSmallestWidthDp > 0) {
2194                 int compatWidth = compatibleWidthLimitDp;
2195                 if (compatWidth <= 0) {
2196                     compatWidth = requiresSmallestWidthDp;
2197                 }
2198                 if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
2199                     smallScreen = -1;
2200                 } else {
2201                     smallScreen = 0;
2202                 }
2203                 if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
2204                     normalScreen = -1;
2205                 } else {
2206                     normalScreen = 0;
2207                 }
2208                 if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
2209                     largeScreen = -1;
2210                 } else {
2211                     largeScreen = 0;
2212                 }
2213                 if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
2214                     xlargeScreen = -1;
2215                 } else {
2216                     xlargeScreen = 0;
2217                 }
2218             }
2219 
2220             // Determine default values for any unspecified screen sizes,
2221             // based on the target SDK of the package.  As of 4 (donut)
2222             // the screen size support was introduced, so all default to
2223             // enabled.
2224             if (smallScreen > 0) {
2225                 smallScreen = targetSdk >= 4 ? -1 : 0;
2226             }
2227             if (normalScreen > 0) {
2228                 normalScreen = -1;
2229             }
2230             if (largeScreen > 0) {
2231                 largeScreen = targetSdk >= 4 ? -1 : 0;
2232             }
2233             if (xlargeScreen > 0) {
2234                 // Introduced in Gingerbread.
2235                 xlargeScreen = targetSdk >= 9 ? -1 : 0;
2236             }
2237             if (anyDensity > 0) {
2238                 anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
2239                         || compatibleWidthLimitDp > 0) ? -1 : 0;
2240             }
2241             printf("supports-screens:");
2242             if (smallScreen != 0) {
2243                 printf(" 'small'");
2244             }
2245             if (normalScreen != 0) {
2246                 printf(" 'normal'");
2247             }
2248             if (largeScreen != 0) {
2249                 printf(" 'large'");
2250             }
2251             if (xlargeScreen != 0) {
2252                 printf(" 'xlarge'");
2253             }
2254             printf("\n");
2255             printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
2256             if (requiresSmallestWidthDp > 0) {
2257                 printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
2258             }
2259             if (compatibleWidthLimitDp > 0) {
2260                 printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
2261             }
2262             if (largestWidthLimitDp > 0) {
2263                 printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
2264             }
2265 
2266             printf("locales:");
2267             const size_t NL = locales.size();
2268             for (size_t i=0; i<NL; i++) {
2269                 const char* localeStr =  locales[i].string();
2270                 if (localeStr == NULL || strlen(localeStr) == 0) {
2271                     localeStr = "--_--";
2272                 }
2273                 printf(" '%s'", localeStr);
2274             }
2275             printf("\n");
2276 
2277             printf("densities:");
2278             const size_t ND = densities.size();
2279             for (size_t i=0; i<ND; i++) {
2280                 printf(" '%d'", densities[i]);
2281             }
2282             printf("\n");
2283 
2284             AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
2285             if (dir != NULL) {
2286                 if (dir->getFileCount() > 0) {
2287                     SortedVector<String8> architectures;
2288                     for (size_t i=0; i<dir->getFileCount(); i++) {
2289                         architectures.add(ResTable::normalizeForOutput(
2290                                 dir->getFileName(i).string()));
2291                     }
2292 
2293                     bool outputAltNativeCode = false;
2294                     // A multiArch package is one that contains 64-bit and
2295                     // 32-bit versions of native code and expects 3rd-party
2296                     // apps to load these native code libraries. Since most
2297                     // 64-bit systems also support 32-bit apps, the apps
2298                     // loading this multiArch package's code may be either
2299                     // 32-bit or 64-bit.
2300                     if (hasMultiArch) {
2301                         // If this is a multiArch package, report the 64-bit
2302                         // version only. Then as a separate entry, report the
2303                         // rest.
2304                         //
2305                         // If we report the 32-bit architecture, this APK will
2306                         // be installed on a 32-bit device, causing a large waste
2307                         // of bandwidth and disk space. This assumes that
2308                         // the developer of the multiArch package has also
2309                         // made a version that is 32-bit only.
2310                         String8 intel64("x86_64");
2311                         String8 arm64("arm64-v8a");
2312                         ssize_t index = architectures.indexOf(intel64);
2313                         if (index < 0) {
2314                             index = architectures.indexOf(arm64);
2315                         }
2316 
2317                         if (index >= 0) {
2318                             printf("native-code: '%s'\n", architectures[index].string());
2319                             architectures.removeAt(index);
2320                             outputAltNativeCode = true;
2321                         }
2322                     }
2323 
2324                     const size_t archCount = architectures.size();
2325                     if (archCount > 0) {
2326                         if (outputAltNativeCode) {
2327                             printf("alt-");
2328                         }
2329                         printf("native-code:");
2330                         for (size_t i = 0; i < archCount; i++) {
2331                             printf(" '%s'", architectures[i].string());
2332                         }
2333                         printf("\n");
2334                     }
2335                 }
2336                 delete dir;
2337             }
2338         } else if (strcmp("badger", option) == 0) {
2339             printf("%s", CONSOLE_DATA);
2340         } else if (strcmp("configurations", option) == 0) {
2341             Vector<ResTable_config> configs;
2342             res.getConfigurations(&configs);
2343             const size_t N = configs.size();
2344             for (size_t i=0; i<N; i++) {
2345                 printf("%s\n", configs[i].toString().string());
2346             }
2347         } else {
2348             fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
2349             goto bail;
2350         }
2351     }
2352 
2353     result = NO_ERROR;
2354 
2355 bail:
2356     if (SourcePos::hasErrors()) {
2357         SourcePos::printErrors(stderr);
2358     }
2359 
2360     if (asset) {
2361         delete asset;
2362     }
2363     return (result != NO_ERROR);
2364 }
2365 
2366 
2367 /*
2368  * Handle the "add" command, which wants to add files to a new or
2369  * pre-existing archive.
2370  */
doAdd(Bundle * bundle)2371 int doAdd(Bundle* bundle)
2372 {
2373     ZipFile* zip = NULL;
2374     status_t result = UNKNOWN_ERROR;
2375     const char* zipFileName;
2376 
2377     if (bundle->getUpdate()) {
2378         /* avoid confusion */
2379         fprintf(stderr, "ERROR: can't use '-u' with add\n");
2380         goto bail;
2381     }
2382 
2383     if (bundle->getFileSpecCount() < 1) {
2384         fprintf(stderr, "ERROR: must specify zip file name\n");
2385         goto bail;
2386     }
2387     zipFileName = bundle->getFileSpecEntry(0);
2388 
2389     if (bundle->getFileSpecCount() < 2) {
2390         fprintf(stderr, "NOTE: nothing to do\n");
2391         goto bail;
2392     }
2393 
2394     zip = openReadWrite(zipFileName, true);
2395     if (zip == NULL) {
2396         fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
2397         goto bail;
2398     }
2399 
2400     for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2401         const char* fileName = bundle->getFileSpecEntry(i);
2402 
2403         if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
2404             printf(" '%s'... (from gzip)\n", fileName);
2405             result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
2406         } else {
2407             if (bundle->getJunkPath()) {
2408                 String8 storageName = String8(fileName).getPathLeaf();
2409                 printf(" '%s' as '%s'...\n", fileName,
2410                         ResTable::normalizeForOutput(storageName.string()).string());
2411                 result = zip->add(fileName, storageName.string(),
2412                                   bundle->getCompressionMethod(), NULL);
2413             } else {
2414                 printf(" '%s'...\n", fileName);
2415                 result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
2416             }
2417         }
2418         if (result != NO_ERROR) {
2419             fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
2420             if (result == NAME_NOT_FOUND) {
2421                 fprintf(stderr, ": file not found\n");
2422             } else if (result == ALREADY_EXISTS) {
2423                 fprintf(stderr, ": already exists in archive\n");
2424             } else {
2425                 fprintf(stderr, "\n");
2426             }
2427             goto bail;
2428         }
2429     }
2430 
2431     result = NO_ERROR;
2432 
2433 bail:
2434     delete zip;
2435     return (result != NO_ERROR);
2436 }
2437 
2438 
2439 /*
2440  * Delete files from an existing archive.
2441  */
doRemove(Bundle * bundle)2442 int doRemove(Bundle* bundle)
2443 {
2444     ZipFile* zip = NULL;
2445     status_t result = UNKNOWN_ERROR;
2446     const char* zipFileName;
2447 
2448     if (bundle->getFileSpecCount() < 1) {
2449         fprintf(stderr, "ERROR: must specify zip file name\n");
2450         goto bail;
2451     }
2452     zipFileName = bundle->getFileSpecEntry(0);
2453 
2454     if (bundle->getFileSpecCount() < 2) {
2455         fprintf(stderr, "NOTE: nothing to do\n");
2456         goto bail;
2457     }
2458 
2459     zip = openReadWrite(zipFileName, false);
2460     if (zip == NULL) {
2461         fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
2462             zipFileName);
2463         goto bail;
2464     }
2465 
2466     for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2467         const char* fileName = bundle->getFileSpecEntry(i);
2468         ZipEntry* entry;
2469 
2470         entry = zip->getEntryByName(fileName);
2471         if (entry == NULL) {
2472             printf(" '%s' NOT FOUND\n", fileName);
2473             continue;
2474         }
2475 
2476         result = zip->remove(entry);
2477 
2478         if (result != NO_ERROR) {
2479             fprintf(stderr, "Unable to delete '%s' from '%s'\n",
2480                 bundle->getFileSpecEntry(i), zipFileName);
2481             goto bail;
2482         }
2483     }
2484 
2485     /* update the archive */
2486     zip->flush();
2487 
2488 bail:
2489     delete zip;
2490     return (result != NO_ERROR);
2491 }
2492 
addResourcesToBuilder(const sp<AaptDir> & dir,const sp<ApkBuilder> & builder,bool ignoreConfig=false)2493 static status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
2494     const size_t numDirs = dir->getDirs().size();
2495     for (size_t i = 0; i < numDirs; i++) {
2496         bool ignore = ignoreConfig;
2497         const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
2498         const char* dirStr = subDir->getLeaf().string();
2499         if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
2500             ignore = true;
2501         }
2502         status_t err = addResourcesToBuilder(subDir, builder, ignore);
2503         if (err != NO_ERROR) {
2504             return err;
2505         }
2506     }
2507 
2508     const size_t numFiles = dir->getFiles().size();
2509     for (size_t i = 0; i < numFiles; i++) {
2510         sp<AaptGroup> gp = dir->getFiles().valueAt(i);
2511         const size_t numConfigs = gp->getFiles().size();
2512         for (size_t j = 0; j < numConfigs; j++) {
2513             status_t err = NO_ERROR;
2514             if (ignoreConfig) {
2515                 err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
2516             } else {
2517                 err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
2518             }
2519             if (err != NO_ERROR) {
2520                 fprintf(stderr, "Failed to add %s (%s) to builder.\n",
2521                         gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
2522                 return err;
2523             }
2524         }
2525     }
2526     return NO_ERROR;
2527 }
2528 
buildApkName(const String8 & original,const sp<ApkSplit> & split)2529 static String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
2530     if (split->isBase()) {
2531         return original;
2532     }
2533 
2534     String8 ext(original.getPathExtension());
2535     if (ext == String8(".apk")) {
2536         return String8::format("%s_%s%s",
2537                 original.getBasePath().string(),
2538                 split->getDirectorySafeName().string(),
2539                 ext.string());
2540     }
2541 
2542     return String8::format("%s_%s", original.string(),
2543             split->getDirectorySafeName().string());
2544 }
2545 
2546 /*
2547  * Package up an asset directory and associated application files.
2548  */
doPackage(Bundle * bundle)2549 int doPackage(Bundle* bundle)
2550 {
2551     const char* outputAPKFile;
2552     int retVal = 1;
2553     status_t err;
2554     sp<AaptAssets> assets;
2555     int N;
2556     FILE* fp;
2557     String8 dependencyFile;
2558     sp<ApkBuilder> builder;
2559 
2560     // -c en_XA or/and ar_XB means do pseudolocalization
2561     sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
2562     err = configFilter->parse(bundle->getConfigurations());
2563     if (err != NO_ERROR) {
2564         goto bail;
2565     }
2566     if (configFilter->containsPseudo()) {
2567         bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
2568     }
2569     if (configFilter->containsPseudoBidi()) {
2570         bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
2571     }
2572 
2573     N = bundle->getFileSpecCount();
2574     if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
2575             && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
2576         fprintf(stderr, "ERROR: no input files\n");
2577         goto bail;
2578     }
2579 
2580     outputAPKFile = bundle->getOutputAPKFile();
2581 
2582     // Make sure the filenames provided exist and are of the appropriate type.
2583     if (outputAPKFile) {
2584         FileType type;
2585         type = getFileType(outputAPKFile);
2586         if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
2587             fprintf(stderr,
2588                 "ERROR: output file '%s' exists but is not regular file\n",
2589                 outputAPKFile);
2590             goto bail;
2591         }
2592     }
2593 
2594     // Load the assets.
2595     assets = new AaptAssets();
2596 
2597     // Set up the resource gathering in assets if we're going to generate
2598     // dependency files. Every time we encounter a resource while slurping
2599     // the tree, we'll add it to these stores so we have full resource paths
2600     // to write to a dependency file.
2601     if (bundle->getGenDependencies()) {
2602         sp<FilePathStore> resPathStore = new FilePathStore;
2603         assets->setFullResPaths(resPathStore);
2604         sp<FilePathStore> assetPathStore = new FilePathStore;
2605         assets->setFullAssetPaths(assetPathStore);
2606     }
2607 
2608     err = assets->slurpFromArgs(bundle);
2609     if (err < 0) {
2610         goto bail;
2611     }
2612 
2613     if (bundle->getVerbose()) {
2614         assets->print(String8());
2615     }
2616 
2617     // Create the ApkBuilder, which will collect the compiled files
2618     // to write to the final APK (or sets of APKs if we are building
2619     // a Split APK.
2620     builder = new ApkBuilder(configFilter);
2621 
2622     // If we are generating a Split APK, find out which configurations to split on.
2623     if (bundle->getSplitConfigurations().size() > 0) {
2624         const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
2625         const size_t numSplits = splitStrs.size();
2626         for (size_t i = 0; i < numSplits; i++) {
2627             std::set<ConfigDescription> configs;
2628             if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
2629                 fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
2630                 goto bail;
2631             }
2632 
2633             err = builder->createSplitForConfigs(configs);
2634             if (err != NO_ERROR) {
2635                 goto bail;
2636             }
2637         }
2638     }
2639 
2640     // If they asked for any fileAs that need to be compiled, do so.
2641     if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
2642         err = buildResources(bundle, assets, builder);
2643         if (err != 0) {
2644             goto bail;
2645         }
2646     }
2647 
2648     // At this point we've read everything and processed everything.  From here
2649     // on out it's just writing output files.
2650     if (SourcePos::hasErrors()) {
2651         goto bail;
2652     }
2653 
2654     // Update symbols with information about which ones are needed as Java symbols.
2655     assets->applyJavaSymbols();
2656     if (SourcePos::hasErrors()) {
2657         goto bail;
2658     }
2659 
2660     // If we've been asked to generate a dependency file, do that here
2661     if (bundle->getGenDependencies()) {
2662         // If this is the packaging step, generate the dependency file next to
2663         // the output apk (e.g. bin/resources.ap_.d)
2664         if (outputAPKFile) {
2665             dependencyFile = String8(outputAPKFile);
2666             // Add the .d extension to the dependency file.
2667             dependencyFile.append(".d");
2668         } else {
2669             // Else if this is the R.java dependency generation step,
2670             // generate the dependency file in the R.java package subdirectory
2671             // e.g. gen/com/foo/app/R.java.d
2672             dependencyFile = String8(bundle->getRClassDir());
2673             dependencyFile.appendPath("R.java.d");
2674         }
2675         // Make sure we have a clean dependency file to start with
2676         fp = fopen(dependencyFile, "w");
2677         fclose(fp);
2678     }
2679 
2680     // Write out R.java constants
2681     if (!assets->havePrivateSymbols()) {
2682         if (bundle->getCustomPackage() == NULL) {
2683             // Write the R.java file into the appropriate class directory
2684             // e.g. gen/com/foo/app/R.java
2685             err = writeResourceSymbols(bundle, assets, assets->getPackage(), true,
2686                     bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2687         } else {
2688             const String8 customPkg(bundle->getCustomPackage());
2689             err = writeResourceSymbols(bundle, assets, customPkg, true,
2690                     bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2691         }
2692         if (err < 0) {
2693             goto bail;
2694         }
2695         // If we have library files, we're going to write our R.java file into
2696         // the appropriate class directory for those libraries as well.
2697         // e.g. gen/com/foo/app/lib/R.java
2698         if (bundle->getExtraPackages() != NULL) {
2699             // Split on colon
2700             String8 libs(bundle->getExtraPackages());
2701             char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
2702             while (packageString != NULL) {
2703                 // Write the R.java file out with the correct package name
2704                 err = writeResourceSymbols(bundle, assets, String8(packageString), true,
2705                         bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2706                 if (err < 0) {
2707                     goto bail;
2708                 }
2709                 packageString = strtok(NULL, ":");
2710             }
2711             libs.unlockBuffer();
2712         }
2713     } else {
2714         err = writeResourceSymbols(bundle, assets, assets->getPackage(), false, false);
2715         if (err < 0) {
2716             goto bail;
2717         }
2718         err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true, false);
2719         if (err < 0) {
2720             goto bail;
2721         }
2722     }
2723 
2724     // Write out the ProGuard file
2725     err = writeProguardFile(bundle, assets);
2726     if (err < 0) {
2727         goto bail;
2728     }
2729 
2730     // Write out the Main Dex ProGuard file
2731     err = writeMainDexProguardFile(bundle, assets);
2732     if (err < 0) {
2733         goto bail;
2734     }
2735 
2736     // Write the apk
2737     if (outputAPKFile) {
2738         // Gather all resources and add them to the APK Builder. The builder will then
2739         // figure out which Split they belong in.
2740         err = addResourcesToBuilder(assets, builder);
2741         if (err != NO_ERROR) {
2742             goto bail;
2743         }
2744 
2745         const Vector<sp<ApkSplit> >& splits = builder->getSplits();
2746         const size_t numSplits = splits.size();
2747         for (size_t i = 0; i < numSplits; i++) {
2748             const sp<ApkSplit>& split = splits[i];
2749             String8 outputPath = buildApkName(String8(outputAPKFile), split);
2750             err = writeAPK(bundle, outputPath, split);
2751             if (err != NO_ERROR) {
2752                 fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
2753                 goto bail;
2754             }
2755         }
2756     }
2757 
2758     // If we've been asked to generate a dependency file, we need to finish up here.
2759     // the writeResourceSymbols and writeAPK functions have already written the target
2760     // half of the dependency file, now we need to write the prerequisites. (files that
2761     // the R.java file or .ap_ file depend on)
2762     if (bundle->getGenDependencies()) {
2763         // Now that writeResourceSymbols or writeAPK has taken care of writing
2764         // the targets to our dependency file, we'll write the prereqs
2765         fp = fopen(dependencyFile, "a+");
2766         fprintf(fp, " : ");
2767         bool includeRaw = (outputAPKFile != NULL);
2768         err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
2769         // Also manually add the AndroidManifeset since it's not under res/ or assets/
2770         // and therefore was not added to our pathstores during slurping
2771         fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
2772         fclose(fp);
2773     }
2774 
2775     retVal = 0;
2776 bail:
2777     if (SourcePos::hasErrors()) {
2778         SourcePos::printErrors(stderr);
2779     }
2780     return retVal;
2781 }
2782 
2783 /*
2784  * Do PNG Crunching
2785  * PRECONDITIONS
2786  *  -S flag points to a source directory containing drawable* folders
2787  *  -C flag points to destination directory. The folder structure in the
2788  *     source directory will be mirrored to the destination (cache) directory
2789  *
2790  * POSTCONDITIONS
2791  *  Destination directory will be updated to match the PNG files in
2792  *  the source directory.
2793  */
doCrunch(Bundle * bundle)2794 int doCrunch(Bundle* bundle)
2795 {
2796     fprintf(stdout, "Crunching PNG Files in ");
2797     fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
2798     fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
2799 
2800     updatePreProcessedCache(bundle);
2801 
2802     return NO_ERROR;
2803 }
2804 
2805 /*
2806  * Do PNG Crunching on a single flag
2807  *  -i points to a single png file
2808  *  -o points to a single png output file
2809  */
doSingleCrunch(Bundle * bundle)2810 int doSingleCrunch(Bundle* bundle)
2811 {
2812     fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
2813     fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
2814 
2815     String8 input(bundle->getSingleCrunchInputFile());
2816     String8 output(bundle->getSingleCrunchOutputFile());
2817 
2818     if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
2819         // we can't return the status_t as it gets truncate to the lower 8 bits.
2820         return 42;
2821     }
2822 
2823     return NO_ERROR;
2824 }
2825 
runInDaemonMode(Bundle * bundle)2826 int runInDaemonMode(Bundle* bundle) {
2827     std::cout << "Ready" << std::endl;
2828     for (std::string cmd; std::getline(std::cin, cmd);) {
2829         if (cmd == "quit") {
2830             return NO_ERROR;
2831         } else if (cmd == "s") {
2832             // Two argument crunch
2833             std::string inputFile, outputFile;
2834             std::getline(std::cin, inputFile);
2835             std::getline(std::cin, outputFile);
2836             bundle->setSingleCrunchInputFile(inputFile.c_str());
2837             bundle->setSingleCrunchOutputFile(outputFile.c_str());
2838             std::cout << "Crunching " << inputFile << std::endl;
2839             if (doSingleCrunch(bundle) != NO_ERROR) {
2840                 std::cout << "Error" << std::endl;
2841             }
2842             std::cout << "Done" << std::endl;
2843         } else {
2844             // in case of invalid command, just bail out.
2845             std::cerr << "Unknown command" << std::endl;
2846             return -1;
2847         }
2848     }
2849     return -1;
2850 }
2851 
2852 char CONSOLE_DATA[2925] = {
2853     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2854     32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2855     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2856     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2857     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
2858     86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
2859     62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2860     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2861     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
2862     81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
2863     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2864     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2865     32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
2866     59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2867     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2868     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
2869     59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
2870     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2871     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2872     32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
2873     58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
2874     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2875     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2876     47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
2877     121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2878     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2879     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
2880     81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
2881     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2882     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2883     32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
2884     59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2885     32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2886     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
2887     59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
2888     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2889     32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2890     32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
2891     70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
2892     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2893     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2894     32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
2895     81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2896     32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2897     32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
2898     81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
2899     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2900     32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
2901     59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
2902     60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2903     32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
2904     61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
2905     61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
2906     46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2907     32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2908     59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
2909     109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
2910     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
2911     67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2912     59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
2913     61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
2914     32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
2915     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
2916     73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2917     59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2918     32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
2919     59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
2920     46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
2921     97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
2922     46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
2923     119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
2924     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
2925     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2926     32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
2927     119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2928     59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
2929     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2930     32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
2931     81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
2932     87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2933     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
2934     81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
2935     45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
2936     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2937     32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2938     81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
2939     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2940     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
2941     59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
2942     59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2943     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2944     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
2945     81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
2946     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2947     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2948     32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2949     81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2950     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2951     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
2952     81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
2953     32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2954     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2955     32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2956     81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
2957     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2958     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2959     58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
2960     61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2961     32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2962     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
2963     81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
2964     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2965     32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2966     32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2967     81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2968     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2969     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
2970     59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
2971     59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2972     32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2973     32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
2974     58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
2975     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2976     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2977     61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
2978     59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
2979     32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
2980     32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
2981     32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
2982     61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2983     32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2984     32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
2985     59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
2986     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
2987     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
2988     59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
2989     59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2990     32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2991     32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2992     32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2993     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2994     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2995     46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
2996     46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2997     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2998     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
2999     59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
3000     59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3001     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3002     32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
3003     32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
3004     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
3005     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
3006     59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
3007     59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3008     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3009     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
3010     32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
3011     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3012     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3013     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3014     32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3015     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10
3016   };
3017