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