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