2 // Copyright 2006 The Android Open Source Project
4 // Android Asset Packaging Tool main entry point.
7 #include "ApkBuilder.h"
11 #include "ResourceFilter.h"
12 #include "ResourceTable.h"
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>
30 using namespace android;
33 #define AAPT_VERSION ""
37 * Show version info. All the cool kids do it.
39 int doVersion(Bundle* bundle)
41 if (bundle->getFileSpecCount() != 0) {
42 printf("(ignoring extra arguments)\n");
44 printf("Android Asset Packaging Tool, v0.2-" AAPT_VERSION "\n");
51 * Open the file read only. The call fails if the file doesn't exist.
53 * Returns NULL on failure.
55 ZipFile* openReadOnly(const char* fileName)
61 result = zip->open(fileName, ZipFile::kOpenReadOnly);
62 if (result != NO_ERROR) {
63 if (result == NAME_NOT_FOUND) {
64 fprintf(stderr, "ERROR: '%s' not found\n", fileName);
65 } else if (result == PERMISSION_DENIED) {
66 fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
68 fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
79 * Open the file read-write. The file will be created if it doesn't
80 * already exist and "okayToCreate" is set.
82 * Returns NULL on failure.
84 ZipFile* openReadWrite(const char* fileName, bool okayToCreate)
90 flags = ZipFile::kOpenReadWrite;
92 flags |= ZipFile::kOpenCreate;
96 result = zip->open(fileName, flags);
97 if (result != NO_ERROR) {
109 * Return a short string describing the compression method.
111 const char* compressionName(int method)
113 if (method == ZipEntry::kCompressStored) {
115 } else if (method == ZipEntry::kCompressDeflated) {
123 * Return the percent reduction in size (0% == no compression).
125 int calcPercent(long uncompressedLen, long compressedLen)
127 if (!uncompressedLen) {
130 return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
135 * Handle the "list" command, which can be a simple file dump or
138 * The verbose listing closely matches the output of the Info-ZIP "unzip"
141 int doList(Bundle* bundle)
145 const ZipEntry* entry;
146 long totalUncLen, totalCompLen;
147 const char* zipFileName;
149 if (bundle->getFileSpecCount() != 1) {
150 fprintf(stderr, "ERROR: specify zip file name (only)\n");
153 zipFileName = bundle->getFileSpecEntry(0);
155 zip = openReadOnly(zipFileName);
162 if (bundle->getVerbose()) {
163 printf("Archive: %s\n", zipFileName);
165 " Length Method Size Ratio Offset Date Time CRC-32 Name\n");
167 "-------- ------ ------- ----- ------- ---- ---- ------ ----\n");
170 totalUncLen = totalCompLen = 0;
172 count = zip->getNumEntries();
173 for (i = 0; i < count; i++) {
174 entry = zip->getEntryByIndex(i);
175 if (bundle->getVerbose()) {
179 when = entry->getModWhen();
180 strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
183 printf("%8ld %-7.7s %7ld %3d%% %8zd %s %08lx %s\n",
184 (long) entry->getUncompressedLen(),
185 compressionName(entry->getCompressionMethod()),
186 (long) entry->getCompressedLen(),
187 calcPercent(entry->getUncompressedLen(),
188 entry->getCompressedLen()),
189 (size_t) entry->getLFHOffset(),
192 entry->getFileName());
194 printf("%s\n", entry->getFileName());
197 totalUncLen += entry->getUncompressedLen();
198 totalCompLen += entry->getCompressedLen();
201 if (bundle->getVerbose()) {
203 "-------- ------- --- -------\n");
204 printf("%8ld %7ld %2d%% %d files\n",
207 calcPercent(totalUncLen, totalCompLen),
208 zip->getNumEntries());
211 if (bundle->getAndroidList()) {
213 if (!assets.addAssetPath(String8(zipFileName), NULL)) {
214 fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
219 static const bool kHaveAndroidOs = true;
221 static const bool kHaveAndroidOs = false;
223 const ResTable& res = assets.getResources(false);
224 if (!kHaveAndroidOs) {
225 printf("\nResource table:\n");
229 Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
230 Asset::ACCESS_BUFFER);
231 if (manifestAsset == NULL) {
232 printf("\nNo AndroidManifest.xml found.\n");
234 printf("\nAndroid manifest:\n");
236 tree.setTo(manifestAsset->getBuffer(true),
237 manifestAsset->getLength());
238 printXMLBlock(&tree);
240 delete manifestAsset;
250 static void printResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree,
251 uint32_t attrRes, String8 attrLabel, String8* outError)
254 AaptXml::getResolvedResourceAttribute(resTable, tree, attrRes, &value, outError);
255 if (*outError != "") {
256 *outError = "error print resolved resource attribute";
259 if (value.dataType == Res_value::TYPE_STRING) {
260 String8 result = AaptXml::getResolvedAttribute(resTable, tree, attrRes, outError);
261 printf("%s='%s'", attrLabel.string(),
262 ResTable::normalizeForOutput(result.string()).string());
263 } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
264 value.dataType <= Res_value::TYPE_LAST_INT) {
265 printf("%s='%d'", attrLabel.string(), value.data);
267 printf("%s='0x%x'", attrLabel.string(), (int)value.data);
271 // These are attribute resource constants for the platform, as found
274 LABEL_ATTR = 0x01010001,
275 ICON_ATTR = 0x01010002,
276 NAME_ATTR = 0x01010003,
277 PERMISSION_ATTR = 0x01010006,
278 EXPORTED_ATTR = 0x01010010,
279 GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
280 RESOURCE_ATTR = 0x01010025,
281 DEBUGGABLE_ATTR = 0x0101000f,
282 VALUE_ATTR = 0x01010024,
283 VERSION_CODE_ATTR = 0x0101021b,
284 VERSION_NAME_ATTR = 0x0101021c,
285 SCREEN_ORIENTATION_ATTR = 0x0101001e,
286 MIN_SDK_VERSION_ATTR = 0x0101020c,
287 MAX_SDK_VERSION_ATTR = 0x01010271,
288 REQ_TOUCH_SCREEN_ATTR = 0x01010227,
289 REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
290 REQ_HARD_KEYBOARD_ATTR = 0x01010229,
291 REQ_NAVIGATION_ATTR = 0x0101022a,
292 REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
293 TARGET_SDK_VERSION_ATTR = 0x01010270,
294 TEST_ONLY_ATTR = 0x01010272,
295 ANY_DENSITY_ATTR = 0x0101026c,
296 GL_ES_VERSION_ATTR = 0x01010281,
297 SMALL_SCREEN_ATTR = 0x01010284,
298 NORMAL_SCREEN_ATTR = 0x01010285,
299 LARGE_SCREEN_ATTR = 0x01010286,
300 XLARGE_SCREEN_ATTR = 0x010102bf,
301 REQUIRED_ATTR = 0x0101028e,
302 INSTALL_LOCATION_ATTR = 0x010102b7,
303 SCREEN_SIZE_ATTR = 0x010102ca,
304 SCREEN_DENSITY_ATTR = 0x010102cb,
305 REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
306 COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
307 LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
308 PUBLIC_KEY_ATTR = 0x010103a6,
309 CATEGORY_ATTR = 0x010103e8,
310 BANNER_ATTR = 0x10103f2,
311 ISGAME_ATTR = 0x10103f4,
314 String8 getComponentName(String8 &pkgName, String8 &componentName) {
315 ssize_t idx = componentName.find(".");
316 String8 retStr(pkgName);
318 retStr += componentName;
319 } else if (idx < 0) {
321 retStr += componentName;
323 return componentName;
328 static void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
330 ResXMLTree::event_code_t code;
333 printf("compatible-screens:");
334 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
335 if (code == ResXMLTree::END_TAG) {
342 if (code != ResXMLTree::START_TAG) {
346 const char16_t* ctag16 = tree.getElementName(&len);
347 if (ctag16 == NULL) {
348 *outError = "failed to get XML element name (bad string pool)";
352 if (tag == "screen") {
353 int32_t screenSize = AaptXml::getIntegerAttribute(tree,
355 int32_t screenDensity = AaptXml::getIntegerAttribute(tree,
356 SCREEN_DENSITY_ATTR);
357 if (screenSize > 0 && screenDensity > 0) {
362 printf("'%d/%d'", screenSize, screenDensity);
369 static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
370 printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
371 if (maxSdkVersion != -1) {
372 printf(" maxSdkVersion='%d'", maxSdkVersion);
377 printf("optional-permission: name='%s'",
378 ResTable::normalizeForOutput(name.string()).string());
379 if (maxSdkVersion != -1) {
380 printf(" maxSdkVersion='%d'", maxSdkVersion);
386 static void printUsesPermissionSdk23(const String8& name, int maxSdkVersion=-1) {
387 printf("uses-permission-sdk-23: ");
389 printf("name='%s'", ResTable::normalizeForOutput(name.string()).string());
390 if (maxSdkVersion != -1) {
391 printf(" maxSdkVersion='%d'", maxSdkVersion);
396 static void printUsesImpliedPermission(const String8& name, const String8& reason) {
397 printf("uses-implied-permission: name='%s' reason='%s'\n",
398 ResTable::normalizeForOutput(name.string()).string(),
399 ResTable::normalizeForOutput(reason.string()).string());
402 Vector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost,
403 String8 *outError = NULL)
405 Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
406 if (aidAsset == NULL) {
407 if (outError != NULL) *outError = "xml resource does not exist";
408 return Vector<String8>();
411 const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
413 bool withinApduService = false;
414 Vector<String8> categories;
418 tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
422 ResXMLTree::event_code_t code;
423 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
424 if (code == ResXMLTree::END_TAG) {
426 const char16_t* ctag16 = tree.getElementName(&len);
427 if (ctag16 == NULL) {
428 *outError = "failed to get XML element name (bad string pool)";
429 return Vector<String8>();
433 if (depth == 0 && tag == serviceTagName) {
434 withinApduService = false;
437 } else if (code == ResXMLTree::START_TAG) {
439 const char16_t* ctag16 = tree.getElementName(&len);
440 if (ctag16 == NULL) {
441 *outError = "failed to get XML element name (bad string pool)";
442 return Vector<String8>();
447 if (tag == serviceTagName) {
448 withinApduService = true;
450 } else if (depth == 2 && withinApduService) {
451 if (tag == "aid-group") {
452 String8 category = AaptXml::getAttribute(tree, CATEGORY_ATTR, &error);
454 if (outError != NULL) *outError = error;
455 return Vector<String8>();
458 categories.add(category);
467 static void printComponentPresence(const char* componentName) {
468 printf("provides-component:'%s'\n", componentName);
472 * Represents a feature that has been automatically added due to
473 * a pre-requisite or some other reason.
475 struct ImpliedFeature {
476 ImpliedFeature() : impliedBySdk23(false) {}
477 ImpliedFeature(const String8& n, bool sdk23) : name(n), impliedBySdk23(sdk23) {}
480 * Name of the implied feature.
485 * Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)?
490 * List of human-readable reasons for why this feature was implied.
492 SortedVector<String8> reasons;
496 Feature() : required(false), version(-1) {}
497 Feature(bool required, int32_t version = -1) : required(required), version(version) {}
500 * Whether the feature is required.
505 * What version of the feature is requested.
511 * Represents a <feature-group> tag in the AndroidManifest.xml
513 struct FeatureGroup {
514 FeatureGroup() : openGLESVersion(-1) {}
517 * Human readable label
522 * Explicit features defined in the group
524 KeyedVector<String8, Feature> features;
527 * OpenGL ES version required
532 static bool hasFeature(const char* name, const FeatureGroup& grp,
533 const KeyedVector<String8, ImpliedFeature>& implied) {
535 ssize_t idx = grp.features.indexOfKey(name8);
537 idx = implied.indexOfKey(name8);
542 static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
543 const char* name, const char* reason, bool sdk23) {
545 ssize_t idx = impliedFeatures->indexOfKey(name8);
547 idx = impliedFeatures->add(name8, ImpliedFeature(name8, sdk23));
550 ImpliedFeature* feature = &impliedFeatures->editValueAt(idx);
552 // A non-sdk 23 implied feature takes precedence.
553 if (feature->impliedBySdk23 && !sdk23) {
554 feature->impliedBySdk23 = false;
556 feature->reasons.add(String8(reason));
559 static void printFeatureGroupImpl(const FeatureGroup& grp,
560 const KeyedVector<String8, ImpliedFeature>* impliedFeatures) {
561 printf("feature-group: label='%s'\n", grp.label.string());
563 if (grp.openGLESVersion > 0) {
564 printf(" uses-gl-es: '0x%x'\n", grp.openGLESVersion);
567 const size_t numFeatures = grp.features.size();
568 for (size_t i = 0; i < numFeatures; i++) {
569 const Feature& feature = grp.features[i];
570 const bool required = feature.required;
571 const int32_t version = feature.version;
573 const String8& featureName = grp.features.keyAt(i);
574 printf(" uses-feature%s: name='%s'", (required ? "" : "-not-required"),
575 ResTable::normalizeForOutput(featureName.string()).string());
578 printf(" version='%d'", version);
583 const size_t numImpliedFeatures =
584 (impliedFeatures != NULL) ? impliedFeatures->size() : 0;
585 for (size_t i = 0; i < numImpliedFeatures; i++) {
586 const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i);
587 if (grp.features.indexOfKey(impliedFeature.name) >= 0) {
588 // The feature is explicitly set, no need to use implied
593 String8 printableFeatureName(ResTable::normalizeForOutput(
594 impliedFeature.name.string()));
595 const char* sdk23Suffix = impliedFeature.impliedBySdk23 ? "-sdk-23" : "";
597 printf(" uses-feature%s: name='%s'\n", sdk23Suffix, printableFeatureName.string());
598 printf(" uses-implied-feature%s: name='%s' reason='", sdk23Suffix,
599 printableFeatureName.string());
600 const size_t numReasons = impliedFeature.reasons.size();
601 for (size_t j = 0; j < numReasons; j++) {
602 printf("%s", impliedFeature.reasons[j].string());
603 if (j + 2 < numReasons) {
605 } else if (j + 1 < numReasons) {
613 static void printFeatureGroup(const FeatureGroup& grp) {
614 printFeatureGroupImpl(grp, NULL);
617 static void printDefaultFeatureGroup(const FeatureGroup& grp,
618 const KeyedVector<String8, ImpliedFeature>& impliedFeatures) {
619 printFeatureGroupImpl(grp, &impliedFeatures);
622 static void addParentFeatures(FeatureGroup* grp, const String8& name) {
623 if (name == "android.hardware.camera.autofocus" ||
624 name == "android.hardware.camera.flash") {
625 grp->features.add(String8("android.hardware.camera"), Feature(true));
626 } else if (name == "android.hardware.location.gps" ||
627 name == "android.hardware.location.network") {
628 grp->features.add(String8("android.hardware.location"), Feature(true));
629 } else if (name == "android.hardware.faketouch.multitouch") {
630 grp->features.add(String8("android.hardware.faketouch"), Feature(true));
631 } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
632 name == "android.hardware.faketouch.multitouch.jazzhands") {
633 grp->features.add(String8("android.hardware.faketouch.multitouch"), Feature(true));
634 grp->features.add(String8("android.hardware.faketouch"), Feature(true));
635 } else if (name == "android.hardware.touchscreen.multitouch") {
636 grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
637 } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
638 name == "android.hardware.touchscreen.multitouch.jazzhands") {
639 grp->features.add(String8("android.hardware.touchscreen.multitouch"), Feature(true));
640 grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
641 } else if (name == "android.hardware.opengles.aep") {
642 const int openGLESVersion31 = 0x00030001;
643 if (openGLESVersion31 > grp->openGLESVersion) {
644 grp->openGLESVersion = openGLESVersion31;
649 static void addImpliedFeaturesForPermission(const int targetSdk, const String8& name,
650 KeyedVector<String8, ImpliedFeature>* impliedFeatures,
651 bool impliedBySdk23Permission) {
652 if (name == "android.permission.CAMERA") {
653 addImpliedFeature(impliedFeatures, "android.hardware.camera",
654 String8::format("requested %s permission", name.string())
655 .string(), impliedBySdk23Permission);
656 } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
657 addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
658 String8::format("requested %s permission", name.string())
659 .string(), impliedBySdk23Permission);
660 addImpliedFeature(impliedFeatures, "android.hardware.location",
661 String8::format("requested %s permission", name.string())
662 .string(), impliedBySdk23Permission);
663 } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
664 addImpliedFeature(impliedFeatures, "android.hardware.location",
665 String8::format("requested %s permission", name.string())
666 .string(), impliedBySdk23Permission);
667 } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
668 addImpliedFeature(impliedFeatures, "android.hardware.location.network",
669 String8::format("requested %s permission", name.string())
670 .string(), impliedBySdk23Permission);
671 addImpliedFeature(impliedFeatures, "android.hardware.location",
672 String8::format("requested %s permission", name.string())
673 .string(), impliedBySdk23Permission);
674 } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
675 name == "android.permission.INSTALL_LOCATION_PROVIDER") {
676 addImpliedFeature(impliedFeatures, "android.hardware.location",
677 String8::format("requested %s permission", name.string())
678 .string(), impliedBySdk23Permission);
679 } else if (name == "android.permission.BLUETOOTH" ||
680 name == "android.permission.BLUETOOTH_ADMIN") {
682 addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
683 String8::format("requested %s permission", name.string())
684 .string(), impliedBySdk23Permission);
685 addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
686 "targetSdkVersion > 4", impliedBySdk23Permission);
688 } else if (name == "android.permission.RECORD_AUDIO") {
689 addImpliedFeature(impliedFeatures, "android.hardware.microphone",
690 String8::format("requested %s permission", name.string())
691 .string(), impliedBySdk23Permission);
692 } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
693 name == "android.permission.CHANGE_WIFI_STATE" ||
694 name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
695 addImpliedFeature(impliedFeatures, "android.hardware.wifi",
696 String8::format("requested %s permission", name.string())
697 .string(), impliedBySdk23Permission);
698 } else if (name == "android.permission.CALL_PHONE" ||
699 name == "android.permission.CALL_PRIVILEGED" ||
700 name == "android.permission.MODIFY_PHONE_STATE" ||
701 name == "android.permission.PROCESS_OUTGOING_CALLS" ||
702 name == "android.permission.READ_SMS" ||
703 name == "android.permission.RECEIVE_SMS" ||
704 name == "android.permission.RECEIVE_MMS" ||
705 name == "android.permission.RECEIVE_WAP_PUSH" ||
706 name == "android.permission.SEND_SMS" ||
707 name == "android.permission.WRITE_APN_SETTINGS" ||
708 name == "android.permission.WRITE_SMS") {
709 addImpliedFeature(impliedFeatures, "android.hardware.telephony",
710 String8("requested a telephony permission").string(),
711 impliedBySdk23Permission);
716 * Handle the "dump" command, to extract select data from an archive.
718 extern char CONSOLE_DATA[2925]; // see EOF
719 int doDump(Bundle* bundle)
721 status_t result = UNKNOWN_ERROR;
723 if (bundle->getFileSpecCount() < 1) {
724 fprintf(stderr, "ERROR: no dump option specified\n");
728 if (bundle->getFileSpecCount() < 2) {
729 fprintf(stderr, "ERROR: no dump file specified\n");
733 const char* option = bundle->getFileSpecEntry(0);
734 const char* filename = bundle->getFileSpecEntry(1);
737 int32_t assetsCookie;
738 if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
739 fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
743 // Make a dummy config for retrieving resources... we need to supply
744 // non-default values for some configs so that we can retrieve resources
745 // in the app that don't have a default. The most important of these is
746 // the API version because key resources like icons will have an implicit
747 // version if they are using newer config types like density.
748 ResTable_config config;
749 memset(&config, 0, sizeof(ResTable_config));
750 config.language[0] = 'e';
751 config.language[1] = 'n';
752 config.country[0] = 'U';
753 config.country[1] = 'S';
754 config.orientation = ResTable_config::ORIENTATION_PORT;
755 config.density = ResTable_config::DENSITY_MEDIUM;
756 config.sdkVersion = 10000; // Very high.
757 config.screenWidthDp = 320;
758 config.screenHeightDp = 480;
759 config.smallestScreenWidthDp = 320;
760 config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL;
761 assets.setConfiguration(config);
763 const ResTable& res = assets.getResources(false);
764 if (res.getError() != NO_ERROR) {
765 fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
769 // Source for AndroidManifest.xml
770 const String8 manifestFile = String8::format("%s@AndroidManifest.xml", filename);
772 // The dynamicRefTable can be null if there are no resources for this asset cookie.
774 const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie);
778 if (strcmp("resources", option) == 0) {
780 res.print(bundle->getValues());
783 } else if (strcmp("strings", option) == 0) {
784 const ResStringPool* pool = res.getTableStringBlock(0);
785 printStringPool(pool);
787 } else if (strcmp("xmltree", option) == 0) {
788 if (bundle->getFileSpecCount() < 3) {
789 fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
793 for (int i=2; i<bundle->getFileSpecCount(); i++) {
794 const char* resname = bundle->getFileSpecEntry(i);
795 ResXMLTree tree(dynamicRefTable);
796 asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
798 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
802 if (tree.setTo(asset->getBuffer(true),
803 asset->getLength()) != NO_ERROR) {
804 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
808 printXMLBlock(&tree);
814 } else if (strcmp("xmlstrings", option) == 0) {
815 if (bundle->getFileSpecCount() < 3) {
816 fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
820 for (int i=2; i<bundle->getFileSpecCount(); i++) {
821 const char* resname = bundle->getFileSpecEntry(i);
822 asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
824 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
828 ResXMLTree tree(dynamicRefTable);
829 if (tree.setTo(asset->getBuffer(true),
830 asset->getLength()) != NO_ERROR) {
831 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
834 printStringPool(&tree.getStrings());
840 asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER);
842 fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
846 ResXMLTree tree(dynamicRefTable);
847 if (tree.setTo(asset->getBuffer(true),
848 asset->getLength()) != NO_ERROR) {
849 fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
854 if (strcmp("permissions", option) == 0) {
856 ResXMLTree::event_code_t code;
858 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
859 code != ResXMLTree::BAD_DOCUMENT) {
860 if (code == ResXMLTree::END_TAG) {
864 if (code != ResXMLTree::START_TAG) {
868 const char16_t* ctag16 = tree.getElementName(&len);
869 if (ctag16 == NULL) {
870 fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
874 //printf("Depth %d tag %s\n", depth, tag.string());
876 if (tag != "manifest") {
877 fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
880 String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
881 printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
882 } else if (depth == 2) {
883 if (tag == "permission") {
885 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
887 fprintf(stderr, "ERROR: %s\n", error.string());
892 fprintf(stderr, "ERROR: missing 'android:name' for permission\n");
895 printf("permission: %s\n",
896 ResTable::normalizeForOutput(name.string()).string());
897 } else if (tag == "uses-permission") {
899 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
901 fprintf(stderr, "ERROR: %s\n", error.string());
906 fprintf(stderr, "ERROR: missing 'android:name' for uses-permission\n");
909 printUsesPermission(name,
910 AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
911 AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
912 } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
914 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
916 fprintf(stderr, "ERROR: %s\n", error.string());
921 fprintf(stderr, "ERROR: missing 'android:name' for "
922 "uses-permission-sdk-23\n");
925 printUsesPermissionSdk23(
927 AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
931 } else if (strcmp("badging", option) == 0) {
932 Vector<String8> locales;
933 res.getLocales(&locales);
935 Vector<ResTable_config> configs;
936 res.getConfigurations(&configs);
937 SortedVector<int> densities;
938 const size_t NC = configs.size();
939 for (size_t i=0; i<NC; i++) {
940 int dens = configs[i].density;
948 ResXMLTree::event_code_t code;
951 bool withinActivity = false;
952 bool isMainActivity = false;
953 bool isLauncherActivity = false;
954 bool isLeanbackLauncherActivity = false;
955 bool isSearchable = false;
956 bool withinApplication = false;
957 bool withinSupportsInput = false;
958 bool withinFeatureGroup = false;
959 bool withinReceiver = false;
960 bool withinService = false;
961 bool withinProvider = false;
962 bool withinIntentFilter = false;
963 bool hasMainActivity = false;
964 bool hasOtherActivities = false;
965 bool hasOtherReceivers = false;
966 bool hasOtherServices = false;
967 bool hasIntentFilter = false;
969 bool hasWallpaperService = false;
970 bool hasImeService = false;
971 bool hasAccessibilityService = false;
972 bool hasPrintService = false;
973 bool hasWidgetReceivers = false;
974 bool hasDeviceAdminReceiver = false;
975 bool hasPaymentService = false;
976 bool hasDocumentsProvider = false;
977 bool hasCameraActivity = false;
978 bool hasCameraSecureActivity = false;
979 bool hasLauncher = false;
980 bool hasNotificationListenerService = false;
981 bool hasDreamService = false;
983 bool actMainActivity = false;
984 bool actWidgetReceivers = false;
985 bool actDeviceAdminEnabled = false;
986 bool actImeService = false;
987 bool actWallpaperService = false;
988 bool actAccessibilityService = false;
989 bool actPrintService = false;
990 bool actHostApduService = false;
991 bool actOffHostApduService = false;
992 bool actDocumentsProvider = false;
993 bool actNotificationListenerService = false;
994 bool actDreamService = false;
995 bool actCamera = false;
996 bool actCameraSecure = false;
997 bool catLauncher = false;
998 bool hasMetaHostPaymentCategory = false;
999 bool hasMetaOffHostPaymentCategory = false;
1001 // These permissions are required by services implementing services
1002 // the system binds to (IME, Accessibility, PrintServices, etc.)
1003 bool hasBindDeviceAdminPermission = false;
1004 bool hasBindInputMethodPermission = false;
1005 bool hasBindAccessibilityServicePermission = false;
1006 bool hasBindPrintServicePermission = false;
1007 bool hasBindNfcServicePermission = false;
1008 bool hasRequiredSafAttributes = false;
1009 bool hasBindNotificationListenerServicePermission = false;
1010 bool hasBindDreamServicePermission = false;
1012 // These two implement the implicit permissions that are granted
1013 // to pre-1.6 applications.
1014 bool hasWriteExternalStoragePermission = false;
1015 bool hasReadPhoneStatePermission = false;
1017 // If an app requests write storage, they will also get read storage.
1018 bool hasReadExternalStoragePermission = false;
1020 // Implement transition to read and write call log.
1021 bool hasReadContactsPermission = false;
1022 bool hasWriteContactsPermission = false;
1023 bool hasReadCallLogPermission = false;
1024 bool hasWriteCallLogPermission = false;
1026 // If an app declares itself as multiArch, we report the
1027 // native libraries differently.
1028 bool hasMultiArch = false;
1030 // This next group of variables is used to implement a group of
1031 // backward-compatibility heuristics necessitated by the addition of
1032 // some new uses-feature constants in 2.1 and 2.2. In most cases, the
1033 // heuristic is "if an app requests a permission but doesn't explicitly
1034 // request the corresponding <uses-feature>, presume it's there anyway".
1036 // 2.2 also added some other features that apps can request, but that
1037 // have no corresponding permission, so we cannot implement any
1038 // back-compatibility heuristic for them. The below are thus unnecessary
1039 // (but are retained here for documentary purposes.)
1040 //bool specCompassFeature = false;
1041 //bool specAccelerometerFeature = false;
1042 //bool specProximityFeature = false;
1043 //bool specAmbientLightFeature = false;
1044 //bool specLiveWallpaperFeature = false;
1047 int smallScreen = 1;
1048 int normalScreen = 1;
1049 int largeScreen = 1;
1050 int xlargeScreen = 1;
1052 int requiresSmallestWidthDp = 0;
1053 int compatibleWidthLimitDp = 0;
1054 int largestWidthLimitDp = 0;
1056 String8 activityName;
1057 String8 activityLabel;
1058 String8 activityIcon;
1059 String8 activityBanner;
1060 String8 receiverName;
1061 String8 serviceName;
1062 Vector<String8> supportedInput;
1064 FeatureGroup commonFeatures;
1065 Vector<FeatureGroup> featureGroups;
1066 KeyedVector<String8, ImpliedFeature> impliedFeatures;
1068 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
1069 code != ResXMLTree::BAD_DOCUMENT) {
1070 if (code == ResXMLTree::END_TAG) {
1073 if (withinSupportsInput && !supportedInput.isEmpty()) {
1074 printf("supports-input: '");
1075 const size_t N = supportedInput.size();
1076 for (size_t i=0; i<N; i++) {
1077 printf("%s", ResTable::normalizeForOutput(
1078 supportedInput[i].string()).string());
1085 supportedInput.clear();
1087 withinApplication = false;
1088 withinSupportsInput = false;
1089 withinFeatureGroup = false;
1090 } else if (depth < 3) {
1091 if (withinActivity && isMainActivity) {
1092 String8 aName(getComponentName(pkg, activityName));
1093 if (isLauncherActivity) {
1094 printf("launchable-activity:");
1095 if (aName.length() > 0) {
1096 printf(" name='%s' ",
1097 ResTable::normalizeForOutput(aName.string()).string());
1099 printf(" label='%s' icon='%s'\n",
1100 ResTable::normalizeForOutput(activityLabel.string())
1102 ResTable::normalizeForOutput(activityIcon.string())
1105 if (isLeanbackLauncherActivity) {
1106 printf("leanback-launchable-activity:");
1107 if (aName.length() > 0) {
1108 printf(" name='%s' ",
1109 ResTable::normalizeForOutput(aName.string()).string());
1111 printf(" label='%s' icon='%s' banner='%s'\n",
1112 ResTable::normalizeForOutput(activityLabel.string())
1114 ResTable::normalizeForOutput(activityIcon.string())
1116 ResTable::normalizeForOutput(activityBanner.string())
1120 if (!hasIntentFilter) {
1121 hasOtherActivities |= withinActivity;
1122 hasOtherReceivers |= withinReceiver;
1123 hasOtherServices |= withinService;
1125 if (withinService) {
1126 hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
1127 hasBindNfcServicePermission);
1128 hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
1129 hasBindNfcServicePermission);
1132 withinActivity = false;
1133 withinService = false;
1134 withinReceiver = false;
1135 withinProvider = false;
1136 hasIntentFilter = false;
1137 isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false;
1138 } else if (depth < 4) {
1139 if (withinIntentFilter) {
1140 if (withinActivity) {
1141 hasMainActivity |= actMainActivity;
1142 hasLauncher |= catLauncher;
1143 hasCameraActivity |= actCamera;
1144 hasCameraSecureActivity |= actCameraSecure;
1145 hasOtherActivities |=
1146 !actMainActivity && !actCamera && !actCameraSecure;
1147 } else if (withinReceiver) {
1148 hasWidgetReceivers |= actWidgetReceivers;
1149 hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
1150 hasBindDeviceAdminPermission);
1151 hasOtherReceivers |=
1152 (!actWidgetReceivers && !actDeviceAdminEnabled);
1153 } else if (withinService) {
1154 hasImeService |= actImeService;
1155 hasWallpaperService |= actWallpaperService;
1156 hasAccessibilityService |= (actAccessibilityService &&
1157 hasBindAccessibilityServicePermission);
1159 (actPrintService && hasBindPrintServicePermission);
1160 hasNotificationListenerService |= actNotificationListenerService &&
1161 hasBindNotificationListenerServicePermission;
1162 hasDreamService |= actDreamService && hasBindDreamServicePermission;
1163 hasOtherServices |= (!actImeService && !actWallpaperService &&
1164 !actAccessibilityService && !actPrintService &&
1165 !actHostApduService && !actOffHostApduService &&
1166 !actNotificationListenerService);
1167 } else if (withinProvider) {
1168 hasDocumentsProvider |=
1169 actDocumentsProvider && hasRequiredSafAttributes;
1172 withinIntentFilter = false;
1176 if (code != ResXMLTree::START_TAG) {
1181 const char16_t* ctag16 = tree.getElementName(&len);
1182 if (ctag16 == NULL) {
1183 fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
1186 String8 tag(ctag16);
1187 //printf("Depth %d, %s\n", depth, tag.string());
1189 if (tag != "manifest") {
1190 fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
1193 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
1194 printf("package: name='%s' ",
1195 ResTable::normalizeForOutput(pkg.string()).string());
1196 int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR,
1199 fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n",
1203 if (versionCode > 0) {
1204 printf("versionCode='%d' ", versionCode);
1206 printf("versionCode='' ");
1208 String8 versionName = AaptXml::getResolvedAttribute(res, tree,
1209 VERSION_NAME_ATTR, &error);
1211 fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n",
1215 printf("versionName='%s'",
1216 ResTable::normalizeForOutput(versionName.string()).string());
1218 String8 splitName = AaptXml::getAttribute(tree, NULL, "split");
1219 if (!splitName.isEmpty()) {
1220 printf(" split='%s'", ResTable::normalizeForOutput(
1221 splitName.string()).string());
1224 String8 platformVersionName = AaptXml::getAttribute(tree, NULL,
1225 "platformBuildVersionName");
1226 printf(" platformBuildVersionName='%s'", platformVersionName.string());
1229 int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree,
1230 INSTALL_LOCATION_ATTR, &error);
1232 fprintf(stderr, "ERROR getting 'android:installLocation' attribute: %s\n",
1237 if (installLocation >= 0) {
1238 printf("install-location:'");
1239 switch (installLocation) {
1244 printf("internalOnly");
1247 printf("preferExternal");
1250 fprintf(stderr, "Invalid installLocation %d\n", installLocation);
1255 } else if (depth == 2) {
1256 withinApplication = false;
1257 if (tag == "application") {
1258 withinApplication = true;
1261 const size_t NL = locales.size();
1262 for (size_t i=0; i<NL; i++) {
1263 const char* localeStr = locales[i].string();
1264 assets.setLocale(localeStr != NULL ? localeStr : "");
1265 String8 llabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
1268 if (localeStr == NULL || strlen(localeStr) == 0) {
1270 printf("application-label:'%s'\n",
1271 ResTable::normalizeForOutput(llabel.string()).string());
1276 printf("application-label-%s:'%s'\n", localeStr,
1277 ResTable::normalizeForOutput(llabel.string()).string());
1282 ResTable_config tmpConfig = config;
1283 const size_t ND = densities.size();
1284 for (size_t i=0; i<ND; i++) {
1285 tmpConfig.density = densities[i];
1286 assets.setConfiguration(tmpConfig);
1287 String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR,
1290 printf("application-icon-%d:'%s'\n", densities[i],
1291 ResTable::normalizeForOutput(icon.string()).string());
1294 assets.setConfiguration(config);
1296 String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR, &error);
1298 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
1302 int32_t testOnly = AaptXml::getIntegerAttribute(tree, TEST_ONLY_ATTR, 0,
1305 fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n",
1310 String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
1313 fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
1317 printf("application: label='%s' ",
1318 ResTable::normalizeForOutput(label.string()).string());
1319 printf("icon='%s'", ResTable::normalizeForOutput(icon.string()).string());
1321 printf(" banner='%s'",
1322 ResTable::normalizeForOutput(banner.string()).string());
1325 if (testOnly != 0) {
1326 printf("testOnly='%d'\n", testOnly);
1329 int32_t isGame = AaptXml::getResolvedIntegerAttribute(res, tree,
1330 ISGAME_ATTR, 0, &error);
1332 fprintf(stderr, "ERROR getting 'android:isGame' attribute: %s\n",
1337 printf("application-isGame\n");
1340 int32_t debuggable = AaptXml::getResolvedIntegerAttribute(res, tree,
1341 DEBUGGABLE_ATTR, 0, &error);
1343 fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n",
1347 if (debuggable != 0) {
1348 printf("application-debuggable\n");
1351 // We must search by name because the multiArch flag hasn't been API
1353 int32_t multiArchIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
1355 if (multiArchIndex >= 0) {
1357 if (tree.getAttributeValue(multiArchIndex, &value) != NO_ERROR) {
1358 if (value.dataType >= Res_value::TYPE_FIRST_INT &&
1359 value.dataType <= Res_value::TYPE_LAST_INT) {
1360 hasMultiArch = value.data;
1364 } else if (tag == "uses-sdk") {
1365 int32_t code = AaptXml::getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR,
1369 String8 name = AaptXml::getResolvedAttribute(res, tree,
1370 MIN_SDK_VERSION_ATTR, &error);
1373 "ERROR getting 'android:minSdkVersion' attribute: %s\n",
1377 if (name == "Donut") targetSdk = 4;
1378 printf("sdkVersion:'%s'\n",
1379 ResTable::normalizeForOutput(name.string()).string());
1380 } else if (code != -1) {
1382 printf("sdkVersion:'%d'\n", code);
1384 code = AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR);
1386 printf("maxSdkVersion:'%d'\n", code);
1388 code = AaptXml::getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
1391 String8 name = AaptXml::getResolvedAttribute(res, tree,
1392 TARGET_SDK_VERSION_ATTR, &error);
1395 "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
1399 if (name == "Donut" && targetSdk < 4) targetSdk = 4;
1400 printf("targetSdkVersion:'%s'\n",
1401 ResTable::normalizeForOutput(name.string()).string());
1402 } else if (code != -1) {
1403 if (targetSdk < code) {
1406 printf("targetSdkVersion:'%d'\n", code);
1408 } else if (tag == "uses-configuration") {
1409 int32_t reqTouchScreen = AaptXml::getIntegerAttribute(tree,
1410 REQ_TOUCH_SCREEN_ATTR, 0);
1411 int32_t reqKeyboardType = AaptXml::getIntegerAttribute(tree,
1412 REQ_KEYBOARD_TYPE_ATTR, 0);
1413 int32_t reqHardKeyboard = AaptXml::getIntegerAttribute(tree,
1414 REQ_HARD_KEYBOARD_ATTR, 0);
1415 int32_t reqNavigation = AaptXml::getIntegerAttribute(tree,
1416 REQ_NAVIGATION_ATTR, 0);
1417 int32_t reqFiveWayNav = AaptXml::getIntegerAttribute(tree,
1418 REQ_FIVE_WAY_NAV_ATTR, 0);
1419 printf("uses-configuration:");
1420 if (reqTouchScreen != 0) {
1421 printf(" reqTouchScreen='%d'", reqTouchScreen);
1423 if (reqKeyboardType != 0) {
1424 printf(" reqKeyboardType='%d'", reqKeyboardType);
1426 if (reqHardKeyboard != 0) {
1427 printf(" reqHardKeyboard='%d'", reqHardKeyboard);
1429 if (reqNavigation != 0) {
1430 printf(" reqNavigation='%d'", reqNavigation);
1432 if (reqFiveWayNav != 0) {
1433 printf(" reqFiveWayNav='%d'", reqFiveWayNav);
1436 } else if (tag == "supports-input") {
1437 withinSupportsInput = true;
1438 } else if (tag == "supports-screens") {
1439 smallScreen = AaptXml::getIntegerAttribute(tree,
1440 SMALL_SCREEN_ATTR, 1);
1441 normalScreen = AaptXml::getIntegerAttribute(tree,
1442 NORMAL_SCREEN_ATTR, 1);
1443 largeScreen = AaptXml::getIntegerAttribute(tree,
1444 LARGE_SCREEN_ATTR, 1);
1445 xlargeScreen = AaptXml::getIntegerAttribute(tree,
1446 XLARGE_SCREEN_ATTR, 1);
1447 anyDensity = AaptXml::getIntegerAttribute(tree,
1448 ANY_DENSITY_ATTR, 1);
1449 requiresSmallestWidthDp = AaptXml::getIntegerAttribute(tree,
1450 REQUIRES_SMALLEST_WIDTH_DP_ATTR, 0);
1451 compatibleWidthLimitDp = AaptXml::getIntegerAttribute(tree,
1452 COMPATIBLE_WIDTH_LIMIT_DP_ATTR, 0);
1453 largestWidthLimitDp = AaptXml::getIntegerAttribute(tree,
1454 LARGEST_WIDTH_LIMIT_DP_ATTR, 0);
1455 } else if (tag == "feature-group") {
1456 withinFeatureGroup = true;
1458 group.label = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR, &error);
1460 fprintf(stderr, "ERROR getting 'android:label' attribute:"
1461 " %s\n", error.string());
1464 featureGroups.add(group);
1466 } else if (tag == "uses-feature") {
1467 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1468 if (name != "" && error == "") {
1469 const char* androidSchema =
1470 "http://schemas.android.com/apk/res/android";
1472 int32_t req = AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1,
1475 SourcePos(manifestFile, tree.getLineNumber()).error(
1476 "failed to read attribute 'android:required': %s",
1481 int32_t version = AaptXml::getIntegerAttribute(tree, androidSchema,
1482 "version", 0, &error);
1484 SourcePos(manifestFile, tree.getLineNumber()).error(
1485 "failed to read attribute 'android:version': %s",
1490 commonFeatures.features.add(name, Feature(req != 0, version));
1492 addParentFeatures(&commonFeatures, name);
1495 int vers = AaptXml::getIntegerAttribute(tree,
1496 GL_ES_VERSION_ATTR, &error);
1498 if (vers > commonFeatures.openGLESVersion) {
1499 commonFeatures.openGLESVersion = vers;
1503 } else if (tag == "uses-permission") {
1504 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1506 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1512 fprintf(stderr, "ERROR: missing 'android:name' for uses-permission\n");
1516 addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, false);
1518 if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
1519 hasWriteExternalStoragePermission = true;
1520 } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
1521 hasReadExternalStoragePermission = true;
1522 } else if (name == "android.permission.READ_PHONE_STATE") {
1523 hasReadPhoneStatePermission = true;
1524 } else if (name == "android.permission.READ_CONTACTS") {
1525 hasReadContactsPermission = true;
1526 } else if (name == "android.permission.WRITE_CONTACTS") {
1527 hasWriteContactsPermission = true;
1528 } else if (name == "android.permission.READ_CALL_LOG") {
1529 hasReadCallLogPermission = true;
1530 } else if (name == "android.permission.WRITE_CALL_LOG") {
1531 hasWriteCallLogPermission = true;
1534 printUsesPermission(name,
1535 AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
1536 AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
1538 } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
1539 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1541 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1547 fprintf(stderr, "ERROR: missing 'android:name' for "
1548 "uses-permission-sdk-23\n");
1552 addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, true);
1554 printUsesPermissionSdk23(
1555 name, AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
1557 } else if (tag == "uses-package") {
1558 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1559 if (name != "" && error == "") {
1560 printf("uses-package:'%s'\n",
1561 ResTable::normalizeForOutput(name.string()).string());
1563 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1567 } else if (tag == "original-package") {
1568 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1569 if (name != "" && error == "") {
1570 printf("original-package:'%s'\n",
1571 ResTable::normalizeForOutput(name.string()).string());
1573 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1577 } else if (tag == "supports-gl-texture") {
1578 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1579 if (name != "" && error == "") {
1580 printf("supports-gl-texture:'%s'\n",
1581 ResTable::normalizeForOutput(name.string()).string());
1583 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1587 } else if (tag == "compatible-screens") {
1588 printCompatibleScreens(tree, &error);
1590 fprintf(stderr, "ERROR getting compatible screens: %s\n",
1595 } else if (tag == "package-verifier") {
1596 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1597 if (name != "" && error == "") {
1598 String8 publicKey = AaptXml::getAttribute(tree, PUBLIC_KEY_ATTR,
1600 if (publicKey != "" && error == "") {
1601 printf("package-verifier: name='%s' publicKey='%s'\n",
1602 ResTable::normalizeForOutput(name.string()).string(),
1603 ResTable::normalizeForOutput(publicKey.string()).string());
1607 } else if (depth == 3) {
1608 withinActivity = false;
1609 withinReceiver = false;
1610 withinService = false;
1611 withinProvider = false;
1612 hasIntentFilter = false;
1613 hasMetaHostPaymentCategory = false;
1614 hasMetaOffHostPaymentCategory = false;
1615 hasBindDeviceAdminPermission = false;
1616 hasBindInputMethodPermission = false;
1617 hasBindAccessibilityServicePermission = false;
1618 hasBindPrintServicePermission = false;
1619 hasBindNfcServicePermission = false;
1620 hasRequiredSafAttributes = false;
1621 hasBindNotificationListenerServicePermission = false;
1622 hasBindDreamServicePermission = false;
1623 if (withinApplication) {
1624 if(tag == "activity") {
1625 withinActivity = true;
1626 activityName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1628 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1633 activityLabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
1636 fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
1641 activityIcon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR,
1644 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
1649 activityBanner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
1652 fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
1657 int32_t orien = AaptXml::getResolvedIntegerAttribute(res, tree,
1658 SCREEN_ORIENTATION_ATTR, &error);
1660 if (orien == 0 || orien == 6 || orien == 8) {
1661 // Requests landscape, sensorLandscape, or reverseLandscape.
1662 addImpliedFeature(&impliedFeatures,
1663 "android.hardware.screen.landscape",
1664 "one or more activities have specified a "
1665 "landscape orientation",
1667 } else if (orien == 1 || orien == 7 || orien == 9) {
1668 // Requests portrait, sensorPortrait, or reversePortrait.
1669 addImpliedFeature(&impliedFeatures,
1670 "android.hardware.screen.portrait",
1671 "one or more activities have specified a "
1672 "portrait orientation",
1676 } else if (tag == "uses-library") {
1677 String8 libraryName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1680 "ERROR getting 'android:name' attribute for uses-library"
1681 " %s\n", error.string());
1684 int req = AaptXml::getIntegerAttribute(tree,
1686 printf("uses-library%s:'%s'\n",
1687 req ? "" : "-not-required", ResTable::normalizeForOutput(
1688 libraryName.string()).string());
1689 } else if (tag == "receiver") {
1690 withinReceiver = true;
1691 receiverName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1695 "ERROR getting 'android:name' attribute for receiver:"
1696 " %s\n", error.string());
1700 String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR,
1703 if (permission == "android.permission.BIND_DEVICE_ADMIN") {
1704 hasBindDeviceAdminPermission = true;
1708 "ERROR getting 'android:permission' attribute for"
1709 " receiver '%s': %s\n",
1710 receiverName.string(), error.string());
1712 } else if (tag == "service") {
1713 withinService = true;
1714 serviceName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1717 fprintf(stderr, "ERROR getting 'android:name' attribute for "
1718 "service:%s\n", error.string());
1722 String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR,
1725 if (permission == "android.permission.BIND_INPUT_METHOD") {
1726 hasBindInputMethodPermission = true;
1727 } else if (permission ==
1728 "android.permission.BIND_ACCESSIBILITY_SERVICE") {
1729 hasBindAccessibilityServicePermission = true;
1730 } else if (permission ==
1731 "android.permission.BIND_PRINT_SERVICE") {
1732 hasBindPrintServicePermission = true;
1733 } else if (permission ==
1734 "android.permission.BIND_NFC_SERVICE") {
1735 hasBindNfcServicePermission = true;
1736 } else if (permission ==
1737 "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
1738 hasBindNotificationListenerServicePermission = true;
1739 } else if (permission == "android.permission.BIND_DREAM_SERVICE") {
1740 hasBindDreamServicePermission = true;
1743 fprintf(stderr, "ERROR getting 'android:permission' attribute for "
1744 "service '%s': %s\n", serviceName.string(), error.string());
1746 } else if (tag == "provider") {
1747 withinProvider = true;
1749 bool exported = AaptXml::getResolvedIntegerAttribute(res, tree,
1750 EXPORTED_ATTR, &error);
1753 "ERROR getting 'android:exported' attribute for provider:"
1754 " %s\n", error.string());
1758 bool grantUriPermissions = AaptXml::getResolvedIntegerAttribute(
1759 res, tree, GRANT_URI_PERMISSIONS_ATTR, &error);
1762 "ERROR getting 'android:grantUriPermissions' attribute for "
1763 "provider: %s\n", error.string());
1767 String8 permission = AaptXml::getResolvedAttribute(res, tree,
1768 PERMISSION_ATTR, &error);
1770 fprintf(stderr, "ERROR getting 'android:permission' attribute for "
1771 "provider: %s\n", error.string());
1775 hasRequiredSafAttributes |= exported && grantUriPermissions &&
1776 permission == "android.permission.MANAGE_DOCUMENTS";
1778 } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
1779 String8 metaDataName = AaptXml::getResolvedAttribute(res, tree,
1782 fprintf(stderr, "ERROR getting 'android:name' attribute for "
1783 "meta-data:%s\n", error.string());
1786 printf("meta-data: name='%s' ",
1787 ResTable::normalizeForOutput(metaDataName.string()).string());
1788 printResolvedResourceAttribute(res, tree, VALUE_ATTR, String8("value"),
1791 // Try looking for a RESOURCE_ATTR
1793 printResolvedResourceAttribute(res, tree, RESOURCE_ATTR,
1794 String8("resource"), &error);
1796 fprintf(stderr, "ERROR getting 'android:value' or "
1797 "'android:resource' attribute for "
1798 "meta-data:%s\n", error.string());
1803 } else if (withinSupportsInput && tag == "input-type") {
1804 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1805 if (name != "" && error == "") {
1806 supportedInput.add(name);
1808 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1813 } else if (withinFeatureGroup && tag == "uses-feature") {
1814 const String8 androidSchema("http://schemas.android.com/apk/res/android");
1815 FeatureGroup& top = featureGroups.editTop();
1817 String8 name = AaptXml::getResolvedAttribute(res, tree, NAME_ATTR, &error);
1818 if (name != "" && error == "") {
1819 Feature feature(true);
1821 int32_t featureVers = AaptXml::getIntegerAttribute(
1822 tree, androidSchema.string(), "version", 0, &error);
1824 feature.version = featureVers;
1826 SourcePos(manifestFile, tree.getLineNumber()).error(
1827 "failed to read attribute 'android:version': %s",
1832 top.features.add(name, feature);
1833 addParentFeatures(&top, name);
1836 int vers = AaptXml::getIntegerAttribute(tree, GL_ES_VERSION_ATTR,
1839 if (vers > top.openGLESVersion) {
1840 top.openGLESVersion = vers;
1845 } else if (depth == 4) {
1846 if (tag == "intent-filter") {
1847 hasIntentFilter = true;
1848 withinIntentFilter = true;
1849 actMainActivity = false;
1850 actWidgetReceivers = false;
1851 actImeService = false;
1852 actWallpaperService = false;
1853 actAccessibilityService = false;
1854 actPrintService = false;
1855 actDeviceAdminEnabled = false;
1856 actHostApduService = false;
1857 actOffHostApduService = false;
1858 actDocumentsProvider = false;
1859 actNotificationListenerService = false;
1860 actDreamService = false;
1862 actCameraSecure = false;
1863 catLauncher = false;
1864 } else if (withinService && tag == "meta-data") {
1865 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1867 fprintf(stderr, "ERROR getting 'android:name' attribute for "
1868 "meta-data tag in service '%s': %s\n", serviceName.string(),
1873 if (name == "android.nfc.cardemulation.host_apdu_service" ||
1874 name == "android.nfc.cardemulation.off_host_apdu_service") {
1875 bool offHost = true;
1876 if (name == "android.nfc.cardemulation.host_apdu_service") {
1880 String8 xmlPath = AaptXml::getResolvedAttribute(res, tree,
1881 RESOURCE_ATTR, &error);
1883 fprintf(stderr, "ERROR getting 'android:resource' attribute for "
1884 "meta-data tag in service '%s': %s\n",
1885 serviceName.string(), error.string());
1889 Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
1892 fprintf(stderr, "ERROR getting AID category for service '%s'\n",
1893 serviceName.string());
1897 const size_t catLen = categories.size();
1898 for (size_t i = 0; i < catLen; i++) {
1899 bool paymentCategory = (categories[i] == "payment");
1901 hasMetaOffHostPaymentCategory |= paymentCategory;
1903 hasMetaHostPaymentCategory |= paymentCategory;
1908 } else if ((depth == 5) && withinIntentFilter) {
1910 if (tag == "action") {
1911 action = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1913 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1918 if (withinActivity) {
1919 if (action == "android.intent.action.MAIN") {
1920 isMainActivity = true;
1921 actMainActivity = true;
1922 } else if (action == "android.media.action.STILL_IMAGE_CAMERA" ||
1923 action == "android.media.action.VIDEO_CAMERA") {
1925 } else if (action == "android.media.action.STILL_IMAGE_CAMERA_SECURE") {
1926 actCameraSecure = true;
1928 } else if (withinReceiver) {
1929 if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
1930 actWidgetReceivers = true;
1931 } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
1932 actDeviceAdminEnabled = true;
1934 } else if (withinService) {
1935 if (action == "android.view.InputMethod") {
1936 actImeService = true;
1937 } else if (action == "android.service.wallpaper.WallpaperService") {
1938 actWallpaperService = true;
1939 } else if (action ==
1940 "android.accessibilityservice.AccessibilityService") {
1941 actAccessibilityService = true;
1942 } else if (action =="android.printservice.PrintService") {
1943 actPrintService = true;
1944 } else if (action ==
1945 "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
1946 actHostApduService = true;
1947 } else if (action ==
1948 "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
1949 actOffHostApduService = true;
1950 } else if (action ==
1951 "android.service.notification.NotificationListenerService") {
1952 actNotificationListenerService = true;
1953 } else if (action == "android.service.dreams.DreamService") {
1954 actDreamService = true;
1956 } else if (withinProvider) {
1957 if (action == "android.content.action.DOCUMENTS_PROVIDER") {
1958 actDocumentsProvider = true;
1961 if (action == "android.intent.action.SEARCH") {
1962 isSearchable = true;
1966 if (tag == "category") {
1967 String8 category = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1969 fprintf(stderr, "ERROR getting 'name' attribute: %s\n",
1973 if (withinActivity) {
1974 if (category == "android.intent.category.LAUNCHER") {
1975 isLauncherActivity = true;
1976 } else if (category == "android.intent.category.LEANBACK_LAUNCHER") {
1977 isLeanbackLauncherActivity = true;
1978 } else if (category == "android.intent.category.HOME") {
1986 // Pre-1.6 implicitly granted permission compatibility logic
1987 if (targetSdk < 4) {
1988 if (!hasWriteExternalStoragePermission) {
1989 printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
1990 printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
1991 String8("targetSdkVersion < 4"));
1992 hasWriteExternalStoragePermission = true;
1994 if (!hasReadPhoneStatePermission) {
1995 printUsesPermission(String8("android.permission.READ_PHONE_STATE"));
1996 printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"),
1997 String8("targetSdkVersion < 4"));
2001 // If the application has requested WRITE_EXTERNAL_STORAGE, we will
2002 // force them to always take READ_EXTERNAL_STORAGE as well. We always
2003 // do this (regardless of target API version) because we can't have
2004 // an app with write permission but not read permission.
2005 if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
2006 printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"));
2007 printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
2008 String8("requested WRITE_EXTERNAL_STORAGE"));
2011 // Pre-JellyBean call log permission compatibility.
2012 if (targetSdk < 16) {
2013 if (!hasReadCallLogPermission && hasReadContactsPermission) {
2014 printUsesPermission(String8("android.permission.READ_CALL_LOG"));
2015 printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
2016 String8("targetSdkVersion < 16 and requested READ_CONTACTS"));
2018 if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
2019 printUsesPermission(String8("android.permission.WRITE_CALL_LOG"));
2020 printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"),
2021 String8("targetSdkVersion < 16 and requested WRITE_CONTACTS"));
2025 // If the app hasn't declared the touchscreen as a feature requirement (either
2026 // directly or implied, required or not), then the faketouch feature is implied.
2027 if (!hasFeature("android.hardware.touchscreen", commonFeatures, impliedFeatures)) {
2028 addImpliedFeature(&impliedFeatures, "android.hardware.faketouch",
2029 "default feature for all apps", false);
2032 const size_t numFeatureGroups = featureGroups.size();
2033 if (numFeatureGroups == 0) {
2034 // If no <feature-group> tags were defined, apply auto-implied features.
2035 printDefaultFeatureGroup(commonFeatures, impliedFeatures);
2038 // <feature-group> tags are defined, so we ignore implied features and
2039 for (size_t i = 0; i < numFeatureGroups; i++) {
2040 FeatureGroup& grp = featureGroups.editItemAt(i);
2042 if (commonFeatures.openGLESVersion > grp.openGLESVersion) {
2043 grp.openGLESVersion = commonFeatures.openGLESVersion;
2046 // Merge the features defined in the top level (not inside a <feature-group>)
2047 // with this feature group.
2048 const size_t numCommonFeatures = commonFeatures.features.size();
2049 for (size_t j = 0; j < numCommonFeatures; j++) {
2050 if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) {
2051 grp.features.add(commonFeatures.features.keyAt(j),
2052 commonFeatures.features[j]);
2056 if (!grp.features.isEmpty()) {
2057 printFeatureGroup(grp);
2063 if (hasWidgetReceivers) {
2064 printComponentPresence("app-widget");
2066 if (hasDeviceAdminReceiver) {
2067 printComponentPresence("device-admin");
2069 if (hasImeService) {
2070 printComponentPresence("ime");
2072 if (hasWallpaperService) {
2073 printComponentPresence("wallpaper");
2075 if (hasAccessibilityService) {
2076 printComponentPresence("accessibility");
2078 if (hasPrintService) {
2079 printComponentPresence("print-service");
2081 if (hasPaymentService) {
2082 printComponentPresence("payment");
2085 printComponentPresence("search");
2087 if (hasDocumentsProvider) {
2088 printComponentPresence("document-provider");
2091 printComponentPresence("launcher");
2093 if (hasNotificationListenerService) {
2094 printComponentPresence("notification-listener");
2096 if (hasDreamService) {
2097 printComponentPresence("dream");
2099 if (hasCameraActivity) {
2100 printComponentPresence("camera");
2102 if (hasCameraSecureActivity) {
2103 printComponentPresence("camera-secure");
2106 if (hasMainActivity) {
2109 if (hasOtherActivities) {
2110 printf("other-activities\n");
2112 if (hasOtherReceivers) {
2113 printf("other-receivers\n");
2115 if (hasOtherServices) {
2116 printf("other-services\n");
2119 // For modern apps, if screen size buckets haven't been specified
2120 // but the new width ranges have, then infer the buckets from them.
2121 if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
2122 && requiresSmallestWidthDp > 0) {
2123 int compatWidth = compatibleWidthLimitDp;
2124 if (compatWidth <= 0) {
2125 compatWidth = requiresSmallestWidthDp;
2127 if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
2132 if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
2137 if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
2142 if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
2149 // Determine default values for any unspecified screen sizes,
2150 // based on the target SDK of the package. As of 4 (donut)
2151 // the screen size support was introduced, so all default to
2153 if (smallScreen > 0) {
2154 smallScreen = targetSdk >= 4 ? -1 : 0;
2156 if (normalScreen > 0) {
2159 if (largeScreen > 0) {
2160 largeScreen = targetSdk >= 4 ? -1 : 0;
2162 if (xlargeScreen > 0) {
2163 // Introduced in Gingerbread.
2164 xlargeScreen = targetSdk >= 9 ? -1 : 0;
2166 if (anyDensity > 0) {
2167 anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
2168 || compatibleWidthLimitDp > 0) ? -1 : 0;
2170 printf("supports-screens:");
2171 if (smallScreen != 0) {
2174 if (normalScreen != 0) {
2175 printf(" 'normal'");
2177 if (largeScreen != 0) {
2180 if (xlargeScreen != 0) {
2181 printf(" 'xlarge'");
2184 printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
2185 if (requiresSmallestWidthDp > 0) {
2186 printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
2188 if (compatibleWidthLimitDp > 0) {
2189 printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
2191 if (largestWidthLimitDp > 0) {
2192 printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
2196 const size_t NL = locales.size();
2197 for (size_t i=0; i<NL; i++) {
2198 const char* localeStr = locales[i].string();
2199 if (localeStr == NULL || strlen(localeStr) == 0) {
2200 localeStr = "--_--";
2202 printf(" '%s'", localeStr);
2206 printf("densities:");
2207 const size_t ND = densities.size();
2208 for (size_t i=0; i<ND; i++) {
2209 printf(" '%d'", densities[i]);
2213 AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
2215 if (dir->getFileCount() > 0) {
2216 SortedVector<String8> architectures;
2217 for (size_t i=0; i<dir->getFileCount(); i++) {
2218 architectures.add(ResTable::normalizeForOutput(
2219 dir->getFileName(i).string()));
2222 bool outputAltNativeCode = false;
2223 // A multiArch package is one that contains 64-bit and
2224 // 32-bit versions of native code and expects 3rd-party
2225 // apps to load these native code libraries. Since most
2226 // 64-bit systems also support 32-bit apps, the apps
2227 // loading this multiArch package's code may be either
2228 // 32-bit or 64-bit.
2230 // If this is a multiArch package, report the 64-bit
2231 // version only. Then as a separate entry, report the
2234 // If we report the 32-bit architecture, this APK will
2235 // be installed on a 32-bit device, causing a large waste
2236 // of bandwidth and disk space. This assumes that
2237 // the developer of the multiArch package has also
2238 // made a version that is 32-bit only.
2239 String8 intel64("x86_64");
2240 String8 arm64("arm64-v8a");
2241 ssize_t index = architectures.indexOf(intel64);
2243 index = architectures.indexOf(arm64);
2247 printf("native-code: '%s'\n", architectures[index].string());
2248 architectures.removeAt(index);
2249 outputAltNativeCode = true;
2253 const size_t archCount = architectures.size();
2254 if (archCount > 0) {
2255 if (outputAltNativeCode) {
2258 printf("native-code:");
2259 for (size_t i = 0; i < archCount; i++) {
2260 printf(" '%s'", architectures[i].string());
2267 } else if (strcmp("badger", option) == 0) {
2268 printf("%s", CONSOLE_DATA);
2269 } else if (strcmp("configurations", option) == 0) {
2270 Vector<ResTable_config> configs;
2271 res.getConfigurations(&configs);
2272 const size_t N = configs.size();
2273 for (size_t i=0; i<N; i++) {
2274 printf("%s\n", configs[i].toString().string());
2277 fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
2288 return (result != NO_ERROR);
2293 * Handle the "add" command, which wants to add files to a new or
2294 * pre-existing archive.
2296 int doAdd(Bundle* bundle)
2298 ZipFile* zip = NULL;
2299 status_t result = UNKNOWN_ERROR;
2300 const char* zipFileName;
2302 if (bundle->getUpdate()) {
2303 /* avoid confusion */
2304 fprintf(stderr, "ERROR: can't use '-u' with add\n");
2308 if (bundle->getFileSpecCount() < 1) {
2309 fprintf(stderr, "ERROR: must specify zip file name\n");
2312 zipFileName = bundle->getFileSpecEntry(0);
2314 if (bundle->getFileSpecCount() < 2) {
2315 fprintf(stderr, "NOTE: nothing to do\n");
2319 zip = openReadWrite(zipFileName, true);
2321 fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
2325 for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2326 const char* fileName = bundle->getFileSpecEntry(i);
2328 if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
2329 printf(" '%s'... (from gzip)\n", fileName);
2330 result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
2332 if (bundle->getJunkPath()) {
2333 String8 storageName = String8(fileName).getPathLeaf();
2334 printf(" '%s' as '%s'...\n", fileName,
2335 ResTable::normalizeForOutput(storageName.string()).string());
2336 result = zip->add(fileName, storageName.string(),
2337 bundle->getCompressionMethod(), NULL);
2339 printf(" '%s'...\n", fileName);
2340 result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
2343 if (result != NO_ERROR) {
2344 fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
2345 if (result == NAME_NOT_FOUND) {
2346 fprintf(stderr, ": file not found\n");
2347 } else if (result == ALREADY_EXISTS) {
2348 fprintf(stderr, ": already exists in archive\n");
2350 fprintf(stderr, "\n");
2360 return (result != NO_ERROR);
2365 * Delete files from an existing archive.
2367 int doRemove(Bundle* bundle)
2369 ZipFile* zip = NULL;
2370 status_t result = UNKNOWN_ERROR;
2371 const char* zipFileName;
2373 if (bundle->getFileSpecCount() < 1) {
2374 fprintf(stderr, "ERROR: must specify zip file name\n");
2377 zipFileName = bundle->getFileSpecEntry(0);
2379 if (bundle->getFileSpecCount() < 2) {
2380 fprintf(stderr, "NOTE: nothing to do\n");
2384 zip = openReadWrite(zipFileName, false);
2386 fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
2391 for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2392 const char* fileName = bundle->getFileSpecEntry(i);
2395 entry = zip->getEntryByName(fileName);
2396 if (entry == NULL) {
2397 printf(" '%s' NOT FOUND\n", fileName);
2401 result = zip->remove(entry);
2403 if (result != NO_ERROR) {
2404 fprintf(stderr, "Unable to delete '%s' from '%s'\n",
2405 bundle->getFileSpecEntry(i), zipFileName);
2410 /* update the archive */
2415 return (result != NO_ERROR);
2418 static status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
2419 const size_t numDirs = dir->getDirs().size();
2420 for (size_t i = 0; i < numDirs; i++) {
2421 bool ignore = ignoreConfig;
2422 const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
2423 const char* dirStr = subDir->getLeaf().string();
2424 if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
2427 status_t err = addResourcesToBuilder(subDir, builder, ignore);
2428 if (err != NO_ERROR) {
2433 const size_t numFiles = dir->getFiles().size();
2434 for (size_t i = 0; i < numFiles; i++) {
2435 sp<AaptGroup> gp = dir->getFiles().valueAt(i);
2436 const size_t numConfigs = gp->getFiles().size();
2437 for (size_t j = 0; j < numConfigs; j++) {
2438 status_t err = NO_ERROR;
2440 err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
2442 err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
2444 if (err != NO_ERROR) {
2445 fprintf(stderr, "Failed to add %s (%s) to builder.\n",
2446 gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
2454 static String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
2455 if (split->isBase()) {
2459 String8 ext(original.getPathExtension());
2460 if (ext == String8(".apk")) {
2461 return String8::format("%s_%s%s",
2462 original.getBasePath().string(),
2463 split->getDirectorySafeName().string(),
2467 return String8::format("%s_%s", original.string(),
2468 split->getDirectorySafeName().string());
2472 * Package up an asset directory and associated application files.
2474 int doPackage(Bundle* bundle)
2476 const char* outputAPKFile;
2479 sp<AaptAssets> assets;
2482 String8 dependencyFile;
2483 sp<ApkBuilder> builder;
2485 // -c en_XA or/and ar_XB means do pseudolocalization
2486 sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
2487 err = configFilter->parse(bundle->getConfigurations());
2488 if (err != NO_ERROR) {
2491 if (configFilter->containsPseudo()) {
2492 bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
2494 if (configFilter->containsPseudoBidi()) {
2495 bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
2498 N = bundle->getFileSpecCount();
2499 if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
2500 && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
2501 fprintf(stderr, "ERROR: no input files\n");
2505 outputAPKFile = bundle->getOutputAPKFile();
2507 // Make sure the filenames provided exist and are of the appropriate type.
2508 if (outputAPKFile) {
2510 type = getFileType(outputAPKFile);
2511 if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
2513 "ERROR: output file '%s' exists but is not regular file\n",
2520 assets = new AaptAssets();
2522 // Set up the resource gathering in assets if we're going to generate
2523 // dependency files. Every time we encounter a resource while slurping
2524 // the tree, we'll add it to these stores so we have full resource paths
2525 // to write to a dependency file.
2526 if (bundle->getGenDependencies()) {
2527 sp<FilePathStore> resPathStore = new FilePathStore;
2528 assets->setFullResPaths(resPathStore);
2529 sp<FilePathStore> assetPathStore = new FilePathStore;
2530 assets->setFullAssetPaths(assetPathStore);
2533 err = assets->slurpFromArgs(bundle);
2538 if (bundle->getVerbose()) {
2539 assets->print(String8());
2542 // Create the ApkBuilder, which will collect the compiled files
2543 // to write to the final APK (or sets of APKs if we are building
2545 builder = new ApkBuilder(configFilter);
2547 // If we are generating a Split APK, find out which configurations to split on.
2548 if (bundle->getSplitConfigurations().size() > 0) {
2549 const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
2550 const size_t numSplits = splitStrs.size();
2551 for (size_t i = 0; i < numSplits; i++) {
2552 std::set<ConfigDescription> configs;
2553 if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
2554 fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
2558 err = builder->createSplitForConfigs(configs);
2559 if (err != NO_ERROR) {
2565 // If they asked for any fileAs that need to be compiled, do so.
2566 if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
2567 err = buildResources(bundle, assets, builder);
2573 // At this point we've read everything and processed everything. From here
2574 // on out it's just writing output files.
2575 if (SourcePos::hasErrors()) {
2579 // Update symbols with information about which ones are needed as Java symbols.
2580 assets->applyJavaSymbols();
2581 if (SourcePos::hasErrors()) {
2585 // If we've been asked to generate a dependency file, do that here
2586 if (bundle->getGenDependencies()) {
2587 // If this is the packaging step, generate the dependency file next to
2588 // the output apk (e.g. bin/resources.ap_.d)
2589 if (outputAPKFile) {
2590 dependencyFile = String8(outputAPKFile);
2591 // Add the .d extension to the dependency file.
2592 dependencyFile.append(".d");
2594 // Else if this is the R.java dependency generation step,
2595 // generate the dependency file in the R.java package subdirectory
2596 // e.g. gen/com/foo/app/R.java.d
2597 dependencyFile = String8(bundle->getRClassDir());
2598 dependencyFile.appendPath("R.java.d");
2600 // Make sure we have a clean dependency file to start with
2601 fp = fopen(dependencyFile, "w");
2605 // Write out R.java constants
2606 if (!assets->havePrivateSymbols()) {
2607 if (bundle->getCustomPackage() == NULL) {
2608 // Write the R.java file into the appropriate class directory
2609 // e.g. gen/com/foo/app/R.java
2610 err = writeResourceSymbols(bundle, assets, assets->getPackage(), true,
2611 bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2613 const String8 customPkg(bundle->getCustomPackage());
2614 err = writeResourceSymbols(bundle, assets, customPkg, true,
2615 bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2620 // If we have library files, we're going to write our R.java file into
2621 // the appropriate class directory for those libraries as well.
2622 // e.g. gen/com/foo/app/lib/R.java
2623 if (bundle->getExtraPackages() != NULL) {
2625 String8 libs(bundle->getExtraPackages());
2626 char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
2627 while (packageString != NULL) {
2628 // Write the R.java file out with the correct package name
2629 err = writeResourceSymbols(bundle, assets, String8(packageString), true,
2630 bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2634 packageString = strtok(NULL, ":");
2636 libs.unlockBuffer();
2639 err = writeResourceSymbols(bundle, assets, assets->getPackage(), false, false);
2643 err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true, false);
2649 // Write out the ProGuard file
2650 err = writeProguardFile(bundle, assets);
2655 // Write out the Main Dex ProGuard file
2656 err = writeMainDexProguardFile(bundle, assets);
2662 if (outputAPKFile) {
2663 // Gather all resources and add them to the APK Builder. The builder will then
2664 // figure out which Split they belong in.
2665 err = addResourcesToBuilder(assets, builder);
2666 if (err != NO_ERROR) {
2670 const Vector<sp<ApkSplit> >& splits = builder->getSplits();
2671 const size_t numSplits = splits.size();
2672 for (size_t i = 0; i < numSplits; i++) {
2673 const sp<ApkSplit>& split = splits[i];
2674 String8 outputPath = buildApkName(String8(outputAPKFile), split);
2675 err = writeAPK(bundle, outputPath, split);
2676 if (err != NO_ERROR) {
2677 fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
2683 // If we've been asked to generate a dependency file, we need to finish up here.
2684 // the writeResourceSymbols and writeAPK functions have already written the target
2685 // half of the dependency file, now we need to write the prerequisites. (files that
2686 // the R.java file or .ap_ file depend on)
2687 if (bundle->getGenDependencies()) {
2688 // Now that writeResourceSymbols or writeAPK has taken care of writing
2689 // the targets to our dependency file, we'll write the prereqs
2690 fp = fopen(dependencyFile, "a+");
2692 bool includeRaw = (outputAPKFile != NULL);
2693 err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
2694 // Also manually add the AndroidManifeset since it's not under res/ or assets/
2695 // and therefore was not added to our pathstores during slurping
2696 fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
2702 if (SourcePos::hasErrors()) {
2703 SourcePos::printErrors(stderr);
2711 * -S flag points to a source directory containing drawable* folders
2712 * -C flag points to destination directory. The folder structure in the
2713 * source directory will be mirrored to the destination (cache) directory
2716 * Destination directory will be updated to match the PNG files in
2717 * the source directory.
2719 int doCrunch(Bundle* bundle)
2721 fprintf(stdout, "Crunching PNG Files in ");
2722 fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
2723 fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
2725 updatePreProcessedCache(bundle);
2731 * Do PNG Crunching on a single flag
2732 * -i points to a single png file
2733 * -o points to a single png output file
2735 int doSingleCrunch(Bundle* bundle)
2737 fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
2738 fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
2740 String8 input(bundle->getSingleCrunchInputFile());
2741 String8 output(bundle->getSingleCrunchOutputFile());
2743 if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
2744 // we can't return the status_t as it gets truncate to the lower 8 bits.
2751 int runInDaemonMode(Bundle* bundle) {
2752 std::cout << "Ready" << std::endl;
2753 for (std::string cmd; std::getline(std::cin, cmd);) {
2754 if (cmd == "quit") {
2756 } else if (cmd == "s") {
2757 // Two argument crunch
2758 std::string inputFile, outputFile;
2759 std::getline(std::cin, inputFile);
2760 std::getline(std::cin, outputFile);
2761 bundle->setSingleCrunchInputFile(inputFile.c_str());
2762 bundle->setSingleCrunchOutputFile(outputFile.c_str());
2763 std::cout << "Crunching " << inputFile << std::endl;
2764 if (doSingleCrunch(bundle) != NO_ERROR) {
2765 std::cout << "Error" << std::endl;
2767 std::cout << "Done" << std::endl;
2769 // in case of invalid command, just bail out.
2770 std::cerr << "Unknown command" << std::endl;
2777 char CONSOLE_DATA[2925] = {
2778 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2779 32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2780 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2781 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2782 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
2783 86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
2784 62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2785 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2786 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
2787 81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
2788 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2789 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2790 32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
2791 59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2792 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2793 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
2794 59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
2795 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2796 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2797 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
2798 58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
2799 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2800 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2801 47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
2802 121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2803 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2804 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
2805 81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
2806 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2807 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2808 32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
2809 59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2810 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2811 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
2812 59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
2813 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2814 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2815 32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
2816 70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
2817 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2818 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2819 32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
2820 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2821 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2822 32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
2823 81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
2824 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2825 32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
2826 59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
2827 60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2828 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
2829 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
2830 61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
2831 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2832 32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2833 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
2834 109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
2835 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
2836 67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2837 59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
2838 61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
2839 32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
2840 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
2841 73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2842 59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2843 32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
2844 59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
2845 46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
2846 97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
2847 46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
2848 119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
2849 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
2850 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2851 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
2852 119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2853 59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
2854 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2855 32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
2856 81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
2857 87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2858 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
2859 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
2860 45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
2861 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2862 32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2863 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
2864 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2865 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
2866 59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
2867 59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2868 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2869 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
2870 81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
2871 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2872 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2873 32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2874 81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2875 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2876 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
2877 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
2878 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2879 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2880 32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2881 81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
2882 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2883 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2884 58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
2885 61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2886 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2887 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
2888 81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
2889 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2890 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2891 32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2892 81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2893 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2894 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
2895 59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
2896 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2897 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2898 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
2899 58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
2900 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2901 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2902 61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
2903 59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
2904 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
2905 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
2906 32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
2907 61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2908 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2909 32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
2910 59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
2911 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
2912 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
2913 59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
2914 59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2915 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2916 32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2917 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2918 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2919 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2920 46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
2921 46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2922 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2923 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
2924 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
2925 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2926 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2927 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
2928 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
2929 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2930 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
2931 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
2932 59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2933 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2934 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
2935 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
2936 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2937 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2938 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2939 32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2940 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10