OSDN Git Service

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