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