OSDN Git Service

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