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