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