Command.cpp revision eaeb19048672337714c1724de7992be8cb3f2124
1// 2// Copyright 2006 The Android Open Source Project 3// 4// Android Asset Packaging Tool main entry point. 5// 6#include "Main.h" 7#include "Bundle.h" 8#include "ResourceFilter.h" 9#include "ResourceTable.h" 10#include "Images.h" 11#include "XMLNode.h" 12 13#include <utils/Log.h> 14#include <utils/threads.h> 15#include <utils/List.h> 16#include <utils/Errors.h> 17 18#include <fcntl.h> 19#include <errno.h> 20 21using namespace android; 22 23/* 24 * Show version info. All the cool kids do it. 25 */ 26int doVersion(Bundle* bundle) 27{ 28 if (bundle->getFileSpecCount() != 0) 29 printf("(ignoring extra arguments)\n"); 30 printf("Android Asset Packaging Tool, v0.2\n"); 31 32 return 0; 33} 34 35 36/* 37 * Open the file read only. The call fails if the file doesn't exist. 38 * 39 * Returns NULL on failure. 40 */ 41ZipFile* openReadOnly(const char* fileName) 42{ 43 ZipFile* zip; 44 status_t result; 45 46 zip = new ZipFile; 47 result = zip->open(fileName, ZipFile::kOpenReadOnly); 48 if (result != NO_ERROR) { 49 if (result == NAME_NOT_FOUND) 50 fprintf(stderr, "ERROR: '%s' not found\n", fileName); 51 else if (result == PERMISSION_DENIED) 52 fprintf(stderr, "ERROR: '%s' access denied\n", fileName); 53 else 54 fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n", 55 fileName); 56 delete zip; 57 return NULL; 58 } 59 60 return zip; 61} 62 63/* 64 * Open the file read-write. The file will be created if it doesn't 65 * already exist and "okayToCreate" is set. 66 * 67 * Returns NULL on failure. 68 */ 69ZipFile* openReadWrite(const char* fileName, bool okayToCreate) 70{ 71 ZipFile* zip = NULL; 72 status_t result; 73 int flags; 74 75 flags = ZipFile::kOpenReadWrite; 76 if (okayToCreate) 77 flags |= ZipFile::kOpenCreate; 78 79 zip = new ZipFile; 80 result = zip->open(fileName, flags); 81 if (result != NO_ERROR) { 82 delete zip; 83 zip = NULL; 84 goto bail; 85 } 86 87bail: 88 return zip; 89} 90 91 92/* 93 * Return a short string describing the compression method. 94 */ 95const char* compressionName(int method) 96{ 97 if (method == ZipEntry::kCompressStored) 98 return "Stored"; 99 else if (method == ZipEntry::kCompressDeflated) 100 return "Deflated"; 101 else 102 return "Unknown"; 103} 104 105/* 106 * Return the percent reduction in size (0% == no compression). 107 */ 108int calcPercent(long uncompressedLen, long compressedLen) 109{ 110 if (!uncompressedLen) 111 return 0; 112 else 113 return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5); 114} 115 116/* 117 * Handle the "list" command, which can be a simple file dump or 118 * a verbose listing. 119 * 120 * The verbose listing closely matches the output of the Info-ZIP "unzip" 121 * command. 122 */ 123int doList(Bundle* bundle) 124{ 125 int result = 1; 126 ZipFile* zip = NULL; 127 const ZipEntry* entry; 128 long totalUncLen, totalCompLen; 129 const char* zipFileName; 130 131 if (bundle->getFileSpecCount() != 1) { 132 fprintf(stderr, "ERROR: specify zip file name (only)\n"); 133 goto bail; 134 } 135 zipFileName = bundle->getFileSpecEntry(0); 136 137 zip = openReadOnly(zipFileName); 138 if (zip == NULL) 139 goto bail; 140 141 int count, i; 142 143 if (bundle->getVerbose()) { 144 printf("Archive: %s\n", zipFileName); 145 printf( 146 " Length Method Size Ratio Offset Date Time CRC-32 Name\n"); 147 printf( 148 "-------- ------ ------- ----- ------- ---- ---- ------ ----\n"); 149 } 150 151 totalUncLen = totalCompLen = 0; 152 153 count = zip->getNumEntries(); 154 for (i = 0; i < count; i++) { 155 entry = zip->getEntryByIndex(i); 156 if (bundle->getVerbose()) { 157 char dateBuf[32]; 158 time_t when; 159 160 when = entry->getModWhen(); 161 strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M", 162 localtime(&when)); 163 164 printf("%8ld %-7.7s %7ld %3d%% %8zd %s %08lx %s\n", 165 (long) entry->getUncompressedLen(), 166 compressionName(entry->getCompressionMethod()), 167 (long) entry->getCompressedLen(), 168 calcPercent(entry->getUncompressedLen(), 169 entry->getCompressedLen()), 170 (size_t) entry->getLFHOffset(), 171 dateBuf, 172 entry->getCRC32(), 173 entry->getFileName()); 174 } else { 175 printf("%s\n", entry->getFileName()); 176 } 177 178 totalUncLen += entry->getUncompressedLen(); 179 totalCompLen += entry->getCompressedLen(); 180 } 181 182 if (bundle->getVerbose()) { 183 printf( 184 "-------- ------- --- -------\n"); 185 printf("%8ld %7ld %2d%% %d files\n", 186 totalUncLen, 187 totalCompLen, 188 calcPercent(totalUncLen, totalCompLen), 189 zip->getNumEntries()); 190 } 191 192 if (bundle->getAndroidList()) { 193 AssetManager assets; 194 if (!assets.addAssetPath(String8(zipFileName), NULL)) { 195 fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n"); 196 goto bail; 197 } 198 199 const ResTable& res = assets.getResources(false); 200 if (&res == NULL) { 201 printf("\nNo resource table found.\n"); 202 } else { 203#ifndef HAVE_ANDROID_OS 204 printf("\nResource table:\n"); 205 res.print(false); 206#endif 207 } 208 209 Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml", 210 Asset::ACCESS_BUFFER); 211 if (manifestAsset == NULL) { 212 printf("\nNo AndroidManifest.xml found.\n"); 213 } else { 214 printf("\nAndroid manifest:\n"); 215 ResXMLTree tree; 216 tree.setTo(manifestAsset->getBuffer(true), 217 manifestAsset->getLength()); 218 printXMLBlock(&tree); 219 } 220 delete manifestAsset; 221 } 222 223 result = 0; 224 225bail: 226 delete zip; 227 return result; 228} 229 230static ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes) 231{ 232 size_t N = tree.getAttributeCount(); 233 for (size_t i=0; i<N; i++) { 234 if (tree.getAttributeNameResID(i) == attrRes) { 235 return (ssize_t)i; 236 } 237 } 238 return -1; 239} 240 241String8 getAttribute(const ResXMLTree& tree, const char* ns, 242 const char* attr, String8* outError) 243{ 244 ssize_t idx = tree.indexOfAttribute(ns, attr); 245 if (idx < 0) { 246 return String8(); 247 } 248 Res_value value; 249 if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 250 if (value.dataType != Res_value::TYPE_STRING) { 251 if (outError != NULL) *outError = "attribute is not a string value"; 252 return String8(); 253 } 254 } 255 size_t len; 256 const uint16_t* str = tree.getAttributeStringValue(idx, &len); 257 return str ? String8(str, len) : String8(); 258} 259 260static String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError) 261{ 262 ssize_t idx = indexOfAttribute(tree, attrRes); 263 if (idx < 0) { 264 return String8(); 265 } 266 Res_value value; 267 if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 268 if (value.dataType != Res_value::TYPE_STRING) { 269 if (outError != NULL) *outError = "attribute is not a string value"; 270 return String8(); 271 } 272 } 273 size_t len; 274 const uint16_t* str = tree.getAttributeStringValue(idx, &len); 275 return str ? String8(str, len) : String8(); 276} 277 278static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, 279 String8* outError, int32_t defValue = -1) 280{ 281 ssize_t idx = indexOfAttribute(tree, attrRes); 282 if (idx < 0) { 283 return defValue; 284 } 285 Res_value value; 286 if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 287 if (value.dataType < Res_value::TYPE_FIRST_INT 288 || value.dataType > Res_value::TYPE_LAST_INT) { 289 if (outError != NULL) *outError = "attribute is not an integer value"; 290 return defValue; 291 } 292 } 293 return value.data; 294} 295 296static int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree, 297 uint32_t attrRes, String8* outError, int32_t defValue = -1) 298{ 299 ssize_t idx = indexOfAttribute(tree, attrRes); 300 if (idx < 0) { 301 return defValue; 302 } 303 Res_value value; 304 if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 305 if (value.dataType == Res_value::TYPE_REFERENCE) { 306 resTable->resolveReference(&value, 0); 307 } 308 if (value.dataType < Res_value::TYPE_FIRST_INT 309 || value.dataType > Res_value::TYPE_LAST_INT) { 310 if (outError != NULL) *outError = "attribute is not an integer value"; 311 return defValue; 312 } 313 } 314 return value.data; 315} 316 317static String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree, 318 uint32_t attrRes, String8* outError) 319{ 320 ssize_t idx = indexOfAttribute(tree, attrRes); 321 if (idx < 0) { 322 return String8(); 323 } 324 Res_value value; 325 if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 326 if (value.dataType == Res_value::TYPE_STRING) { 327 size_t len; 328 const uint16_t* str = tree.getAttributeStringValue(idx, &len); 329 return str ? String8(str, len) : String8(); 330 } 331 resTable->resolveReference(&value, 0); 332 if (value.dataType != Res_value::TYPE_STRING) { 333 if (outError != NULL) *outError = "attribute is not a string value"; 334 return String8(); 335 } 336 } 337 size_t len; 338 const Res_value* value2 = &value; 339 const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len); 340 return str ? String8(str, len) : String8(); 341} 342 343// These are attribute resource constants for the platform, as found 344// in android.R.attr 345enum { 346 LABEL_ATTR = 0x01010001, 347 ICON_ATTR = 0x01010002, 348 NAME_ATTR = 0x01010003, 349 DEBUGGABLE_ATTR = 0x0101000f, 350 VERSION_CODE_ATTR = 0x0101021b, 351 VERSION_NAME_ATTR = 0x0101021c, 352 SCREEN_ORIENTATION_ATTR = 0x0101001e, 353 MIN_SDK_VERSION_ATTR = 0x0101020c, 354 MAX_SDK_VERSION_ATTR = 0x01010271, 355 REQ_TOUCH_SCREEN_ATTR = 0x01010227, 356 REQ_KEYBOARD_TYPE_ATTR = 0x01010228, 357 REQ_HARD_KEYBOARD_ATTR = 0x01010229, 358 REQ_NAVIGATION_ATTR = 0x0101022a, 359 REQ_FIVE_WAY_NAV_ATTR = 0x01010232, 360 TARGET_SDK_VERSION_ATTR = 0x01010270, 361 TEST_ONLY_ATTR = 0x01010272, 362 ANY_DENSITY_ATTR = 0x0101026c, 363 GL_ES_VERSION_ATTR = 0x01010281, 364 SMALL_SCREEN_ATTR = 0x01010284, 365 NORMAL_SCREEN_ATTR = 0x01010285, 366 LARGE_SCREEN_ATTR = 0x01010286, 367 XLARGE_SCREEN_ATTR = 0x010102bf, 368 REQUIRED_ATTR = 0x0101028e, 369 SCREEN_SIZE_ATTR = 0x010102ca, 370 SCREEN_DENSITY_ATTR = 0x010102cb, 371 REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364, 372 COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365, 373 LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366, 374 PUBLIC_KEY_ATTR = 0x010103a6, 375}; 376 377const char *getComponentName(String8 &pkgName, String8 &componentName) { 378 ssize_t idx = componentName.find("."); 379 String8 retStr(pkgName); 380 if (idx == 0) { 381 retStr += componentName; 382 } else if (idx < 0) { 383 retStr += "."; 384 retStr += componentName; 385 } else { 386 return componentName.string(); 387 } 388 return retStr.string(); 389} 390 391static void printCompatibleScreens(ResXMLTree& tree) { 392 size_t len; 393 ResXMLTree::event_code_t code; 394 int depth = 0; 395 bool first = true; 396 printf("compatible-screens:"); 397 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { 398 if (code == ResXMLTree::END_TAG) { 399 depth--; 400 if (depth < 0) { 401 break; 402 } 403 continue; 404 } 405 if (code != ResXMLTree::START_TAG) { 406 continue; 407 } 408 depth++; 409 String8 tag(tree.getElementName(&len)); 410 if (tag == "screen") { 411 int32_t screenSize = getIntegerAttribute(tree, 412 SCREEN_SIZE_ATTR, NULL, -1); 413 int32_t screenDensity = getIntegerAttribute(tree, 414 SCREEN_DENSITY_ATTR, NULL, -1); 415 if (screenSize > 0 && screenDensity > 0) { 416 if (!first) { 417 printf(","); 418 } 419 first = false; 420 printf("'%d/%d'", screenSize, screenDensity); 421 } 422 } 423 } 424 printf("\n"); 425} 426 427/* 428 * Handle the "dump" command, to extract select data from an archive. 429 */ 430extern char CONSOLE_DATA[2925]; // see EOF 431int doDump(Bundle* bundle) 432{ 433 status_t result = UNKNOWN_ERROR; 434 Asset* asset = NULL; 435 436 if (bundle->getFileSpecCount() < 1) { 437 fprintf(stderr, "ERROR: no dump option specified\n"); 438 return 1; 439 } 440 441 if (bundle->getFileSpecCount() < 2) { 442 fprintf(stderr, "ERROR: no dump file specified\n"); 443 return 1; 444 } 445 446 const char* option = bundle->getFileSpecEntry(0); 447 const char* filename = bundle->getFileSpecEntry(1); 448 449 AssetManager assets; 450 void* assetsCookie; 451 if (!assets.addAssetPath(String8(filename), &assetsCookie)) { 452 fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n"); 453 return 1; 454 } 455 456 // Make a dummy config for retrieving resources... we need to supply 457 // non-default values for some configs so that we can retrieve resources 458 // in the app that don't have a default. The most important of these is 459 // the API version because key resources like icons will have an implicit 460 // version if they are using newer config types like density. 461 ResTable_config config; 462 config.language[0] = 'e'; 463 config.language[1] = 'n'; 464 config.country[0] = 'U'; 465 config.country[1] = 'S'; 466 config.orientation = ResTable_config::ORIENTATION_PORT; 467 config.density = ResTable_config::DENSITY_MEDIUM; 468 config.sdkVersion = 10000; // Very high. 469 config.screenWidthDp = 320; 470 config.screenHeightDp = 480; 471 config.smallestScreenWidthDp = 320; 472 assets.setConfiguration(config); 473 474 const ResTable& res = assets.getResources(false); 475 if (&res == NULL) { 476 fprintf(stderr, "ERROR: dump failed because no resource table was found\n"); 477 goto bail; 478 } 479 480 if (strcmp("resources", option) == 0) { 481#ifndef HAVE_ANDROID_OS 482 res.print(bundle->getValues()); 483#endif 484 485 } else if (strcmp("strings", option) == 0) { 486 const ResStringPool* pool = res.getTableStringBlock(0); 487 printStringPool(pool); 488 489 } else if (strcmp("xmltree", option) == 0) { 490 if (bundle->getFileSpecCount() < 3) { 491 fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); 492 goto bail; 493 } 494 495 for (int i=2; i<bundle->getFileSpecCount(); i++) { 496 const char* resname = bundle->getFileSpecEntry(i); 497 ResXMLTree tree; 498 asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); 499 if (asset == NULL) { 500 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); 501 goto bail; 502 } 503 504 if (tree.setTo(asset->getBuffer(true), 505 asset->getLength()) != NO_ERROR) { 506 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); 507 goto bail; 508 } 509 tree.restart(); 510 printXMLBlock(&tree); 511 tree.uninit(); 512 delete asset; 513 asset = NULL; 514 } 515 516 } else if (strcmp("xmlstrings", option) == 0) { 517 if (bundle->getFileSpecCount() < 3) { 518 fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); 519 goto bail; 520 } 521 522 for (int i=2; i<bundle->getFileSpecCount(); i++) { 523 const char* resname = bundle->getFileSpecEntry(i); 524 ResXMLTree tree; 525 asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); 526 if (asset == NULL) { 527 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); 528 goto bail; 529 } 530 531 if (tree.setTo(asset->getBuffer(true), 532 asset->getLength()) != NO_ERROR) { 533 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); 534 goto bail; 535 } 536 printStringPool(&tree.getStrings()); 537 delete asset; 538 asset = NULL; 539 } 540 541 } else { 542 ResXMLTree tree; 543 asset = assets.openNonAsset("AndroidManifest.xml", 544 Asset::ACCESS_BUFFER); 545 if (asset == NULL) { 546 fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n"); 547 goto bail; 548 } 549 550 if (tree.setTo(asset->getBuffer(true), 551 asset->getLength()) != NO_ERROR) { 552 fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n"); 553 goto bail; 554 } 555 tree.restart(); 556 557 if (strcmp("permissions", option) == 0) { 558 size_t len; 559 ResXMLTree::event_code_t code; 560 int depth = 0; 561 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { 562 if (code == ResXMLTree::END_TAG) { 563 depth--; 564 continue; 565 } 566 if (code != ResXMLTree::START_TAG) { 567 continue; 568 } 569 depth++; 570 String8 tag(tree.getElementName(&len)); 571 //printf("Depth %d tag %s\n", depth, tag.string()); 572 if (depth == 1) { 573 if (tag != "manifest") { 574 fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); 575 goto bail; 576 } 577 String8 pkg = getAttribute(tree, NULL, "package", NULL); 578 printf("package: %s\n", pkg.string()); 579 } else if (depth == 2 && tag == "permission") { 580 String8 error; 581 String8 name = getAttribute(tree, NAME_ATTR, &error); 582 if (error != "") { 583 fprintf(stderr, "ERROR: %s\n", error.string()); 584 goto bail; 585 } 586 printf("permission: %s\n", name.string()); 587 } else if (depth == 2 && tag == "uses-permission") { 588 String8 error; 589 String8 name = getAttribute(tree, NAME_ATTR, &error); 590 if (error != "") { 591 fprintf(stderr, "ERROR: %s\n", error.string()); 592 goto bail; 593 } 594 printf("uses-permission: %s\n", name.string()); 595 int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1); 596 if (!req) { 597 printf("optional-permission: %s\n", name.string()); 598 } 599 } 600 } 601 } else if (strcmp("badging", option) == 0) { 602 Vector<String8> locales; 603 res.getLocales(&locales); 604 605 Vector<ResTable_config> configs; 606 res.getConfigurations(&configs); 607 SortedVector<int> densities; 608 const size_t NC = configs.size(); 609 for (size_t i=0; i<NC; i++) { 610 int dens = configs[i].density; 611 if (dens == 0) dens = 160; 612 densities.add(dens); 613 } 614 615 size_t len; 616 ResXMLTree::event_code_t code; 617 int depth = 0; 618 String8 error; 619 bool withinActivity = false; 620 bool isMainActivity = false; 621 bool isLauncherActivity = false; 622 bool isSearchable = false; 623 bool withinApplication = false; 624 bool withinSupportsInput = false; 625 bool withinReceiver = false; 626 bool withinService = false; 627 bool withinIntentFilter = false; 628 bool hasMainActivity = false; 629 bool hasOtherActivities = false; 630 bool hasOtherReceivers = false; 631 bool hasOtherServices = false; 632 bool hasWallpaperService = false; 633 bool hasImeService = false; 634 bool hasWidgetReceivers = false; 635 bool hasIntentFilter = false; 636 bool actMainActivity = false; 637 bool actWidgetReceivers = false; 638 bool actImeService = false; 639 bool actWallpaperService = false; 640 641 // These two implement the implicit permissions that are granted 642 // to pre-1.6 applications. 643 bool hasWriteExternalStoragePermission = false; 644 bool hasReadPhoneStatePermission = false; 645 646 // If an app requests write storage, they will also get read storage. 647 bool hasReadExternalStoragePermission = false; 648 649 // Implement transition to read and write call log. 650 bool hasReadContactsPermission = false; 651 bool hasWriteContactsPermission = false; 652 bool hasReadCallLogPermission = false; 653 bool hasWriteCallLogPermission = false; 654 655 // This next group of variables is used to implement a group of 656 // backward-compatibility heuristics necessitated by the addition of 657 // some new uses-feature constants in 2.1 and 2.2. In most cases, the 658 // heuristic is "if an app requests a permission but doesn't explicitly 659 // request the corresponding <uses-feature>, presume it's there anyway". 660 bool specCameraFeature = false; // camera-related 661 bool specCameraAutofocusFeature = false; 662 bool reqCameraAutofocusFeature = false; 663 bool reqCameraFlashFeature = false; 664 bool hasCameraPermission = false; 665 bool specLocationFeature = false; // location-related 666 bool specNetworkLocFeature = false; 667 bool reqNetworkLocFeature = false; 668 bool specGpsFeature = false; 669 bool reqGpsFeature = false; 670 bool hasMockLocPermission = false; 671 bool hasCoarseLocPermission = false; 672 bool hasGpsPermission = false; 673 bool hasGeneralLocPermission = false; 674 bool specBluetoothFeature = false; // Bluetooth API-related 675 bool hasBluetoothPermission = false; 676 bool specMicrophoneFeature = false; // microphone-related 677 bool hasRecordAudioPermission = false; 678 bool specWiFiFeature = false; 679 bool hasWiFiPermission = false; 680 bool specTelephonyFeature = false; // telephony-related 681 bool reqTelephonySubFeature = false; 682 bool hasTelephonyPermission = false; 683 bool specTouchscreenFeature = false; // touchscreen-related 684 bool specMultitouchFeature = false; 685 bool reqDistinctMultitouchFeature = false; 686 bool specScreenPortraitFeature = false; 687 bool specScreenLandscapeFeature = false; 688 bool reqScreenPortraitFeature = false; 689 bool reqScreenLandscapeFeature = false; 690 // 2.2 also added some other features that apps can request, but that 691 // have no corresponding permission, so we cannot implement any 692 // back-compatibility heuristic for them. The below are thus unnecessary 693 // (but are retained here for documentary purposes.) 694 //bool specCompassFeature = false; 695 //bool specAccelerometerFeature = false; 696 //bool specProximityFeature = false; 697 //bool specAmbientLightFeature = false; 698 //bool specLiveWallpaperFeature = false; 699 700 int targetSdk = 0; 701 int smallScreen = 1; 702 int normalScreen = 1; 703 int largeScreen = 1; 704 int xlargeScreen = 1; 705 int anyDensity = 1; 706 int requiresSmallestWidthDp = 0; 707 int compatibleWidthLimitDp = 0; 708 int largestWidthLimitDp = 0; 709 String8 pkg; 710 String8 activityName; 711 String8 activityLabel; 712 String8 activityIcon; 713 String8 receiverName; 714 String8 serviceName; 715 Vector<String8> supportedInput; 716 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { 717 if (code == ResXMLTree::END_TAG) { 718 depth--; 719 if (depth < 2) { 720 if (withinSupportsInput && !supportedInput.isEmpty()) { 721 printf("supports-input: '"); 722 const size_t N = supportedInput.size(); 723 for (size_t i=0; i<N; i++) { 724 printf("%s", supportedInput[i].string()); 725 if (i != N - 1) { 726 printf("' '"); 727 } else { 728 printf("'\n"); 729 } 730 } 731 supportedInput.clear(); 732 } 733 withinApplication = false; 734 withinSupportsInput = false; 735 } else if (depth < 3) { 736 if (withinActivity && isMainActivity && isLauncherActivity) { 737 const char *aName = getComponentName(pkg, activityName); 738 printf("launchable-activity:"); 739 if (aName != NULL) { 740 printf(" name='%s' ", aName); 741 } 742 printf(" label='%s' icon='%s'\n", 743 activityLabel.string(), 744 activityIcon.string()); 745 } 746 if (!hasIntentFilter) { 747 hasOtherActivities |= withinActivity; 748 hasOtherReceivers |= withinReceiver; 749 hasOtherServices |= withinService; 750 } 751 withinActivity = false; 752 withinService = false; 753 withinReceiver = false; 754 hasIntentFilter = false; 755 isMainActivity = isLauncherActivity = false; 756 } else if (depth < 4) { 757 if (withinIntentFilter) { 758 if (withinActivity) { 759 hasMainActivity |= actMainActivity; 760 hasOtherActivities |= !actMainActivity; 761 } else if (withinReceiver) { 762 hasWidgetReceivers |= actWidgetReceivers; 763 hasOtherReceivers |= !actWidgetReceivers; 764 } else if (withinService) { 765 hasImeService |= actImeService; 766 hasWallpaperService |= actWallpaperService; 767 hasOtherServices |= (!actImeService && !actWallpaperService); 768 } 769 } 770 withinIntentFilter = false; 771 } 772 continue; 773 } 774 if (code != ResXMLTree::START_TAG) { 775 continue; 776 } 777 depth++; 778 String8 tag(tree.getElementName(&len)); 779 //printf("Depth %d, %s\n", depth, tag.string()); 780 if (depth == 1) { 781 if (tag != "manifest") { 782 fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); 783 goto bail; 784 } 785 pkg = getAttribute(tree, NULL, "package", NULL); 786 printf("package: name='%s' ", pkg.string()); 787 int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error); 788 if (error != "") { 789 fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string()); 790 goto bail; 791 } 792 if (versionCode > 0) { 793 printf("versionCode='%d' ", versionCode); 794 } else { 795 printf("versionCode='' "); 796 } 797 String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error); 798 if (error != "") { 799 fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string()); 800 goto bail; 801 } 802 printf("versionName='%s'\n", versionName.string()); 803 } else if (depth == 2) { 804 withinApplication = false; 805 if (tag == "application") { 806 withinApplication = true; 807 808 String8 label; 809 const size_t NL = locales.size(); 810 for (size_t i=0; i<NL; i++) { 811 const char* localeStr = locales[i].string(); 812 assets.setLocale(localeStr != NULL ? localeStr : ""); 813 String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); 814 if (llabel != "") { 815 if (localeStr == NULL || strlen(localeStr) == 0) { 816 label = llabel; 817 printf("application-label:'%s'\n", llabel.string()); 818 } else { 819 if (label == "") { 820 label = llabel; 821 } 822 printf("application-label-%s:'%s'\n", localeStr, 823 llabel.string()); 824 } 825 } 826 } 827 828 ResTable_config tmpConfig = config; 829 const size_t ND = densities.size(); 830 for (size_t i=0; i<ND; i++) { 831 tmpConfig.density = densities[i]; 832 assets.setConfiguration(tmpConfig); 833 String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 834 if (icon != "") { 835 printf("application-icon-%d:'%s'\n", densities[i], icon.string()); 836 } 837 } 838 assets.setConfiguration(config); 839 840 String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 841 if (error != "") { 842 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); 843 goto bail; 844 } 845 int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0); 846 if (error != "") { 847 fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string()); 848 goto bail; 849 } 850 printf("application: label='%s' ", label.string()); 851 printf("icon='%s'\n", icon.string()); 852 if (testOnly != 0) { 853 printf("testOnly='%d'\n", testOnly); 854 } 855 856 int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0); 857 if (error != "") { 858 fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string()); 859 goto bail; 860 } 861 if (debuggable != 0) { 862 printf("application-debuggable\n"); 863 } 864 } else if (tag == "uses-sdk") { 865 int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error); 866 if (error != "") { 867 error = ""; 868 String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error); 869 if (error != "") { 870 fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n", 871 error.string()); 872 goto bail; 873 } 874 if (name == "Donut") targetSdk = 4; 875 printf("sdkVersion:'%s'\n", name.string()); 876 } else if (code != -1) { 877 targetSdk = code; 878 printf("sdkVersion:'%d'\n", code); 879 } 880 code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1); 881 if (code != -1) { 882 printf("maxSdkVersion:'%d'\n", code); 883 } 884 code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error); 885 if (error != "") { 886 error = ""; 887 String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error); 888 if (error != "") { 889 fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n", 890 error.string()); 891 goto bail; 892 } 893 if (name == "Donut" && targetSdk < 4) targetSdk = 4; 894 printf("targetSdkVersion:'%s'\n", name.string()); 895 } else if (code != -1) { 896 if (targetSdk < code) { 897 targetSdk = code; 898 } 899 printf("targetSdkVersion:'%d'\n", code); 900 } 901 } else if (tag == "uses-configuration") { 902 int32_t reqTouchScreen = getIntegerAttribute(tree, 903 REQ_TOUCH_SCREEN_ATTR, NULL, 0); 904 int32_t reqKeyboardType = getIntegerAttribute(tree, 905 REQ_KEYBOARD_TYPE_ATTR, NULL, 0); 906 int32_t reqHardKeyboard = getIntegerAttribute(tree, 907 REQ_HARD_KEYBOARD_ATTR, NULL, 0); 908 int32_t reqNavigation = getIntegerAttribute(tree, 909 REQ_NAVIGATION_ATTR, NULL, 0); 910 int32_t reqFiveWayNav = getIntegerAttribute(tree, 911 REQ_FIVE_WAY_NAV_ATTR, NULL, 0); 912 printf("uses-configuration:"); 913 if (reqTouchScreen != 0) { 914 printf(" reqTouchScreen='%d'", reqTouchScreen); 915 } 916 if (reqKeyboardType != 0) { 917 printf(" reqKeyboardType='%d'", reqKeyboardType); 918 } 919 if (reqHardKeyboard != 0) { 920 printf(" reqHardKeyboard='%d'", reqHardKeyboard); 921 } 922 if (reqNavigation != 0) { 923 printf(" reqNavigation='%d'", reqNavigation); 924 } 925 if (reqFiveWayNav != 0) { 926 printf(" reqFiveWayNav='%d'", reqFiveWayNav); 927 } 928 printf("\n"); 929 } else if (tag == "supports-input") { 930 withinSupportsInput = true; 931 } else if (tag == "supports-screens") { 932 smallScreen = getIntegerAttribute(tree, 933 SMALL_SCREEN_ATTR, NULL, 1); 934 normalScreen = getIntegerAttribute(tree, 935 NORMAL_SCREEN_ATTR, NULL, 1); 936 largeScreen = getIntegerAttribute(tree, 937 LARGE_SCREEN_ATTR, NULL, 1); 938 xlargeScreen = getIntegerAttribute(tree, 939 XLARGE_SCREEN_ATTR, NULL, 1); 940 anyDensity = getIntegerAttribute(tree, 941 ANY_DENSITY_ATTR, NULL, 1); 942 requiresSmallestWidthDp = getIntegerAttribute(tree, 943 REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0); 944 compatibleWidthLimitDp = getIntegerAttribute(tree, 945 COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0); 946 largestWidthLimitDp = getIntegerAttribute(tree, 947 LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0); 948 } else if (tag == "uses-feature") { 949 String8 name = getAttribute(tree, NAME_ATTR, &error); 950 951 if (name != "" && error == "") { 952 int req = getIntegerAttribute(tree, 953 REQUIRED_ATTR, NULL, 1); 954 955 if (name == "android.hardware.camera") { 956 specCameraFeature = true; 957 } else if (name == "android.hardware.camera.autofocus") { 958 // these have no corresponding permission to check for, 959 // but should imply the foundational camera permission 960 reqCameraAutofocusFeature = reqCameraAutofocusFeature || req; 961 specCameraAutofocusFeature = true; 962 } else if (req && (name == "android.hardware.camera.flash")) { 963 // these have no corresponding permission to check for, 964 // but should imply the foundational camera permission 965 reqCameraFlashFeature = true; 966 } else if (name == "android.hardware.location") { 967 specLocationFeature = true; 968 } else if (name == "android.hardware.location.network") { 969 specNetworkLocFeature = true; 970 reqNetworkLocFeature = reqNetworkLocFeature || req; 971 } else if (name == "android.hardware.location.gps") { 972 specGpsFeature = true; 973 reqGpsFeature = reqGpsFeature || req; 974 } else if (name == "android.hardware.bluetooth") { 975 specBluetoothFeature = true; 976 } else if (name == "android.hardware.touchscreen") { 977 specTouchscreenFeature = true; 978 } else if (name == "android.hardware.touchscreen.multitouch") { 979 specMultitouchFeature = true; 980 } else if (name == "android.hardware.touchscreen.multitouch.distinct") { 981 reqDistinctMultitouchFeature = reqDistinctMultitouchFeature || req; 982 } else if (name == "android.hardware.microphone") { 983 specMicrophoneFeature = true; 984 } else if (name == "android.hardware.wifi") { 985 specWiFiFeature = true; 986 } else if (name == "android.hardware.telephony") { 987 specTelephonyFeature = true; 988 } else if (req && (name == "android.hardware.telephony.gsm" || 989 name == "android.hardware.telephony.cdma")) { 990 // these have no corresponding permission to check for, 991 // but should imply the foundational telephony permission 992 reqTelephonySubFeature = true; 993 } else if (name == "android.hardware.screen.portrait") { 994 specScreenPortraitFeature = true; 995 } else if (name == "android.hardware.screen.landscape") { 996 specScreenLandscapeFeature = true; 997 } 998 printf("uses-feature%s:'%s'\n", 999 req ? "" : "-not-required", name.string()); 1000 } else { 1001 int vers = getIntegerAttribute(tree, 1002 GL_ES_VERSION_ATTR, &error); 1003 if (error == "") { 1004 printf("uses-gl-es:'0x%x'\n", vers); 1005 } 1006 } 1007 } else if (tag == "uses-permission") { 1008 String8 name = getAttribute(tree, NAME_ATTR, &error); 1009 if (name != "" && error == "") { 1010 if (name == "android.permission.CAMERA") { 1011 hasCameraPermission = true; 1012 } else if (name == "android.permission.ACCESS_FINE_LOCATION") { 1013 hasGpsPermission = true; 1014 } else if (name == "android.permission.ACCESS_MOCK_LOCATION") { 1015 hasMockLocPermission = true; 1016 } else if (name == "android.permission.ACCESS_COARSE_LOCATION") { 1017 hasCoarseLocPermission = true; 1018 } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" || 1019 name == "android.permission.INSTALL_LOCATION_PROVIDER") { 1020 hasGeneralLocPermission = true; 1021 } else if (name == "android.permission.BLUETOOTH" || 1022 name == "android.permission.BLUETOOTH_ADMIN") { 1023 hasBluetoothPermission = true; 1024 } else if (name == "android.permission.RECORD_AUDIO") { 1025 hasRecordAudioPermission = true; 1026 } else if (name == "android.permission.ACCESS_WIFI_STATE" || 1027 name == "android.permission.CHANGE_WIFI_STATE" || 1028 name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") { 1029 hasWiFiPermission = true; 1030 } else if (name == "android.permission.CALL_PHONE" || 1031 name == "android.permission.CALL_PRIVILEGED" || 1032 name == "android.permission.MODIFY_PHONE_STATE" || 1033 name == "android.permission.PROCESS_OUTGOING_CALLS" || 1034 name == "android.permission.READ_SMS" || 1035 name == "android.permission.RECEIVE_SMS" || 1036 name == "android.permission.RECEIVE_MMS" || 1037 name == "android.permission.RECEIVE_WAP_PUSH" || 1038 name == "android.permission.SEND_SMS" || 1039 name == "android.permission.WRITE_APN_SETTINGS" || 1040 name == "android.permission.WRITE_SMS") { 1041 hasTelephonyPermission = true; 1042 } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") { 1043 hasWriteExternalStoragePermission = true; 1044 } else if (name == "android.permission.READ_EXTERNAL_STORAGE") { 1045 hasReadExternalStoragePermission = true; 1046 } else if (name == "android.permission.READ_PHONE_STATE") { 1047 hasReadPhoneStatePermission = true; 1048 } else if (name == "android.permission.READ_CONTACTS") { 1049 hasReadContactsPermission = true; 1050 } else if (name == "android.permission.WRITE_CONTACTS") { 1051 hasWriteContactsPermission = true; 1052 } else if (name == "android.permission.READ_CALL_LOG") { 1053 hasReadCallLogPermission = true; 1054 } else if (name == "android.permission.WRITE_CALL_LOG") { 1055 hasWriteCallLogPermission = true; 1056 } 1057 printf("uses-permission:'%s'\n", name.string()); 1058 int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1); 1059 if (!req) { 1060 printf("optional-permission:'%s'\n", name.string()); 1061 } 1062 } else { 1063 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1064 error.string()); 1065 goto bail; 1066 } 1067 } else if (tag == "uses-package") { 1068 String8 name = getAttribute(tree, NAME_ATTR, &error); 1069 if (name != "" && error == "") { 1070 printf("uses-package:'%s'\n", name.string()); 1071 } else { 1072 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1073 error.string()); 1074 goto bail; 1075 } 1076 } else if (tag == "original-package") { 1077 String8 name = getAttribute(tree, NAME_ATTR, &error); 1078 if (name != "" && error == "") { 1079 printf("original-package:'%s'\n", name.string()); 1080 } else { 1081 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1082 error.string()); 1083 goto bail; 1084 } 1085 } else if (tag == "supports-gl-texture") { 1086 String8 name = getAttribute(tree, NAME_ATTR, &error); 1087 if (name != "" && error == "") { 1088 printf("supports-gl-texture:'%s'\n", name.string()); 1089 } else { 1090 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1091 error.string()); 1092 goto bail; 1093 } 1094 } else if (tag == "compatible-screens") { 1095 printCompatibleScreens(tree); 1096 depth--; 1097 } else if (tag == "package-verifier") { 1098 String8 name = getAttribute(tree, NAME_ATTR, &error); 1099 if (name != "" && error == "") { 1100 String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error); 1101 if (publicKey != "" && error == "") { 1102 printf("package-verifier: name='%s' publicKey='%s'\n", 1103 name.string(), publicKey.string()); 1104 } 1105 } 1106 } 1107 } else if (depth == 3) { 1108 withinActivity = false; 1109 withinReceiver = false; 1110 withinService = false; 1111 hasIntentFilter = false; 1112 if (withinApplication) { 1113 if(tag == "activity") { 1114 withinActivity = true; 1115 activityName = getAttribute(tree, NAME_ATTR, &error); 1116 if (error != "") { 1117 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1118 error.string()); 1119 goto bail; 1120 } 1121 1122 activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); 1123 if (error != "") { 1124 fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", 1125 error.string()); 1126 goto bail; 1127 } 1128 1129 activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 1130 if (error != "") { 1131 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", 1132 error.string()); 1133 goto bail; 1134 } 1135 1136 int32_t orien = getResolvedIntegerAttribute(&res, tree, 1137 SCREEN_ORIENTATION_ATTR, &error); 1138 if (error == "") { 1139 if (orien == 0 || orien == 6 || orien == 8) { 1140 // Requests landscape, sensorLandscape, or reverseLandscape. 1141 reqScreenLandscapeFeature = true; 1142 } else if (orien == 1 || orien == 7 || orien == 9) { 1143 // Requests portrait, sensorPortrait, or reversePortrait. 1144 reqScreenPortraitFeature = true; 1145 } 1146 } 1147 } else if (tag == "uses-library") { 1148 String8 libraryName = getAttribute(tree, NAME_ATTR, &error); 1149 if (error != "") { 1150 fprintf(stderr, 1151 "ERROR getting 'android:name' attribute for uses-library" 1152 " %s\n", error.string()); 1153 goto bail; 1154 } 1155 int req = getIntegerAttribute(tree, 1156 REQUIRED_ATTR, NULL, 1); 1157 printf("uses-library%s:'%s'\n", 1158 req ? "" : "-not-required", libraryName.string()); 1159 } else if (tag == "receiver") { 1160 withinReceiver = true; 1161 receiverName = getAttribute(tree, NAME_ATTR, &error); 1162 1163 if (error != "") { 1164 fprintf(stderr, 1165 "ERROR getting 'android:name' attribute for receiver:" 1166 " %s\n", error.string()); 1167 goto bail; 1168 } 1169 } else if (tag == "service") { 1170 withinService = true; 1171 serviceName = getAttribute(tree, NAME_ATTR, &error); 1172 1173 if (error != "") { 1174 fprintf(stderr, "ERROR getting 'android:name' attribute for" 1175 " service: %s\n", error.string()); 1176 goto bail; 1177 } 1178 } 1179 } else if (withinSupportsInput && tag == "input-type") { 1180 String8 name = getAttribute(tree, NAME_ATTR, &error); 1181 if (name != "" && error == "") { 1182 supportedInput.add(name); 1183 } else { 1184 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1185 error.string()); 1186 goto bail; 1187 } 1188 } 1189 } else if ((depth == 4) && (tag == "intent-filter")) { 1190 hasIntentFilter = true; 1191 withinIntentFilter = true; 1192 actMainActivity = actWidgetReceivers = actImeService = actWallpaperService = false; 1193 } else if ((depth == 5) && withinIntentFilter){ 1194 String8 action; 1195 if (tag == "action") { 1196 action = getAttribute(tree, NAME_ATTR, &error); 1197 if (error != "") { 1198 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); 1199 goto bail; 1200 } 1201 if (withinActivity) { 1202 if (action == "android.intent.action.MAIN") { 1203 isMainActivity = true; 1204 actMainActivity = true; 1205 } 1206 } else if (withinReceiver) { 1207 if (action == "android.appwidget.action.APPWIDGET_UPDATE") { 1208 actWidgetReceivers = true; 1209 } 1210 } else if (withinService) { 1211 if (action == "android.view.InputMethod") { 1212 actImeService = true; 1213 } else if (action == "android.service.wallpaper.WallpaperService") { 1214 actWallpaperService = true; 1215 } 1216 } 1217 if (action == "android.intent.action.SEARCH") { 1218 isSearchable = true; 1219 } 1220 } 1221 1222 if (tag == "category") { 1223 String8 category = getAttribute(tree, NAME_ATTR, &error); 1224 if (error != "") { 1225 fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string()); 1226 goto bail; 1227 } 1228 if (withinActivity) { 1229 if (category == "android.intent.category.LAUNCHER") { 1230 isLauncherActivity = true; 1231 } 1232 } 1233 } 1234 } 1235 } 1236 1237 // Pre-1.6 implicitly granted permission compatibility logic 1238 if (targetSdk < 4) { 1239 if (!hasWriteExternalStoragePermission) { 1240 printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n"); 1241 printf("uses-implied-permission:'android.permission.WRITE_EXTERNAL_STORAGE'," \ 1242 "'targetSdkVersion < 4'\n"); 1243 hasWriteExternalStoragePermission = true; 1244 } 1245 if (!hasReadPhoneStatePermission) { 1246 printf("uses-permission:'android.permission.READ_PHONE_STATE'\n"); 1247 printf("uses-implied-permission:'android.permission.READ_PHONE_STATE'," \ 1248 "'targetSdkVersion < 4'\n"); 1249 } 1250 } 1251 1252 // If the application has requested WRITE_EXTERNAL_STORAGE, we will 1253 // force them to always take READ_EXTERNAL_STORAGE as well. We always 1254 // do this (regardless of target API version) because we can't have 1255 // an app with write permission but not read permission. 1256 if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) { 1257 printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n"); 1258 printf("uses-implied-permission:'android.permission.READ_EXTERNAL_STORAGE'," \ 1259 "'requested WRITE_EXTERNAL_STORAGE'\n"); 1260 } 1261 1262 // Pre-JellyBean call log permission compatibility. 1263 if (targetSdk < 16) { 1264 if (!hasReadCallLogPermission && hasReadContactsPermission) { 1265 printf("uses-permission:'android.permission.READ_CALL_LOG'\n"); 1266 printf("uses-implied-permission:'android.permission.READ_CALL_LOG'," \ 1267 "'targetSdkVersion < 16 and requested READ_CONTACTS'\n"); 1268 } 1269 if (!hasWriteCallLogPermission && hasWriteContactsPermission) { 1270 printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n"); 1271 printf("uses-implied-permission:'android.permission.WRITE_CALL_LOG'," \ 1272 "'targetSdkVersion < 16 and requested WRITE_CONTACTS'\n"); 1273 } 1274 } 1275 1276 /* The following blocks handle printing "inferred" uses-features, based 1277 * on whether related features or permissions are used by the app. 1278 * Note that the various spec*Feature variables denote whether the 1279 * relevant tag was *present* in the AndroidManfest, not that it was 1280 * present and set to true. 1281 */ 1282 // Camera-related back-compatibility logic 1283 if (!specCameraFeature) { 1284 if (reqCameraFlashFeature) { 1285 // if app requested a sub-feature (autofocus or flash) and didn't 1286 // request the base camera feature, we infer that it meant to 1287 printf("uses-feature:'android.hardware.camera'\n"); 1288 printf("uses-implied-feature:'android.hardware.camera'," \ 1289 "'requested android.hardware.camera.flash feature'\n"); 1290 } else if (reqCameraAutofocusFeature) { 1291 // if app requested a sub-feature (autofocus or flash) and didn't 1292 // request the base camera feature, we infer that it meant to 1293 printf("uses-feature:'android.hardware.camera'\n"); 1294 printf("uses-implied-feature:'android.hardware.camera'," \ 1295 "'requested android.hardware.camera.autofocus feature'\n"); 1296 } else if (hasCameraPermission) { 1297 // if app wants to use camera but didn't request the feature, we infer 1298 // that it meant to, and further that it wants autofocus 1299 // (which was the 1.0 - 1.5 behavior) 1300 printf("uses-feature:'android.hardware.camera'\n"); 1301 if (!specCameraAutofocusFeature) { 1302 printf("uses-feature:'android.hardware.camera.autofocus'\n"); 1303 printf("uses-implied-feature:'android.hardware.camera.autofocus'," \ 1304 "'requested android.permission.CAMERA permission'\n"); 1305 } 1306 } 1307 } 1308 1309 // Location-related back-compatibility logic 1310 if (!specLocationFeature && 1311 (hasMockLocPermission || hasCoarseLocPermission || hasGpsPermission || 1312 hasGeneralLocPermission || reqNetworkLocFeature || reqGpsFeature)) { 1313 // if app either takes a location-related permission or requests one of the 1314 // sub-features, we infer that it also meant to request the base location feature 1315 printf("uses-feature:'android.hardware.location'\n"); 1316 printf("uses-implied-feature:'android.hardware.location'," \ 1317 "'requested a location access permission'\n"); 1318 } 1319 if (!specGpsFeature && hasGpsPermission) { 1320 // if app takes GPS (FINE location) perm but does not request the GPS 1321 // feature, we infer that it meant to 1322 printf("uses-feature:'android.hardware.location.gps'\n"); 1323 printf("uses-implied-feature:'android.hardware.location.gps'," \ 1324 "'requested android.permission.ACCESS_FINE_LOCATION permission'\n"); 1325 } 1326 if (!specNetworkLocFeature && hasCoarseLocPermission) { 1327 // if app takes Network location (COARSE location) perm but does not request the 1328 // network location feature, we infer that it meant to 1329 printf("uses-feature:'android.hardware.location.network'\n"); 1330 printf("uses-implied-feature:'android.hardware.location.network'," \ 1331 "'requested android.permission.ACCESS_COARSE_LOCATION permission'\n"); 1332 } 1333 1334 // Bluetooth-related compatibility logic 1335 if (!specBluetoothFeature && hasBluetoothPermission && (targetSdk > 4)) { 1336 // if app takes a Bluetooth permission but does not request the Bluetooth 1337 // feature, we infer that it meant to 1338 printf("uses-feature:'android.hardware.bluetooth'\n"); 1339 printf("uses-implied-feature:'android.hardware.bluetooth'," \ 1340 "'requested android.permission.BLUETOOTH or android.permission.BLUETOOTH_ADMIN " \ 1341 "permission and targetSdkVersion > 4'\n"); 1342 } 1343 1344 // Microphone-related compatibility logic 1345 if (!specMicrophoneFeature && hasRecordAudioPermission) { 1346 // if app takes the record-audio permission but does not request the microphone 1347 // feature, we infer that it meant to 1348 printf("uses-feature:'android.hardware.microphone'\n"); 1349 printf("uses-implied-feature:'android.hardware.microphone'," \ 1350 "'requested android.permission.RECORD_AUDIO permission'\n"); 1351 } 1352 1353 // WiFi-related compatibility logic 1354 if (!specWiFiFeature && hasWiFiPermission) { 1355 // if app takes one of the WiFi permissions but does not request the WiFi 1356 // feature, we infer that it meant to 1357 printf("uses-feature:'android.hardware.wifi'\n"); 1358 printf("uses-implied-feature:'android.hardware.wifi'," \ 1359 "'requested android.permission.ACCESS_WIFI_STATE, " \ 1360 "android.permission.CHANGE_WIFI_STATE, or " \ 1361 "android.permission.CHANGE_WIFI_MULTICAST_STATE permission'\n"); 1362 } 1363 1364 // Telephony-related compatibility logic 1365 if (!specTelephonyFeature && (hasTelephonyPermission || reqTelephonySubFeature)) { 1366 // if app takes one of the telephony permissions or requests a sub-feature but 1367 // does not request the base telephony feature, we infer that it meant to 1368 printf("uses-feature:'android.hardware.telephony'\n"); 1369 printf("uses-implied-feature:'android.hardware.telephony'," \ 1370 "'requested a telephony-related permission or feature'\n"); 1371 } 1372 1373 // Touchscreen-related back-compatibility logic 1374 if (!specTouchscreenFeature) { // not a typo! 1375 // all apps are presumed to require a touchscreen, unless they explicitly say 1376 // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> 1377 // Note that specTouchscreenFeature is true if the tag is present, regardless 1378 // of whether its value is true or false, so this is safe 1379 printf("uses-feature:'android.hardware.touchscreen'\n"); 1380 printf("uses-implied-feature:'android.hardware.touchscreen'," \ 1381 "'assumed you require a touch screen unless explicitly made optional'\n"); 1382 } 1383 if (!specMultitouchFeature && reqDistinctMultitouchFeature) { 1384 // if app takes one of the telephony permissions or requests a sub-feature but 1385 // does not request the base telephony feature, we infer that it meant to 1386 printf("uses-feature:'android.hardware.touchscreen.multitouch'\n"); 1387 printf("uses-implied-feature:'android.hardware.touchscreen.multitouch'," \ 1388 "'requested android.hardware.touchscreen.multitouch.distinct feature'\n"); 1389 } 1390 1391 // Landscape/portrait-related compatibility logic 1392 if (!specScreenLandscapeFeature && !specScreenPortraitFeature) { 1393 // If the app has specified any activities in its manifest 1394 // that request a specific orientation, then assume that 1395 // orientation is required. 1396 if (reqScreenLandscapeFeature) { 1397 printf("uses-feature:'android.hardware.screen.landscape'\n"); 1398 printf("uses-implied-feature:'android.hardware.screen.landscape'," \ 1399 "'one or more activities have specified a landscape orientation'\n"); 1400 } 1401 if (reqScreenPortraitFeature) { 1402 printf("uses-feature:'android.hardware.screen.portrait'\n"); 1403 printf("uses-implied-feature:'android.hardware.screen.portrait'," \ 1404 "'one or more activities have specified a portrait orientation'\n"); 1405 } 1406 } 1407 1408 if (hasMainActivity) { 1409 printf("main\n"); 1410 } 1411 if (hasWidgetReceivers) { 1412 printf("app-widget\n"); 1413 } 1414 if (hasImeService) { 1415 printf("ime\n"); 1416 } 1417 if (hasWallpaperService) { 1418 printf("wallpaper\n"); 1419 } 1420 if (hasOtherActivities) { 1421 printf("other-activities\n"); 1422 } 1423 if (isSearchable) { 1424 printf("search\n"); 1425 } 1426 if (hasOtherReceivers) { 1427 printf("other-receivers\n"); 1428 } 1429 if (hasOtherServices) { 1430 printf("other-services\n"); 1431 } 1432 1433 // For modern apps, if screen size buckets haven't been specified 1434 // but the new width ranges have, then infer the buckets from them. 1435 if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0 1436 && requiresSmallestWidthDp > 0) { 1437 int compatWidth = compatibleWidthLimitDp; 1438 if (compatWidth <= 0) compatWidth = requiresSmallestWidthDp; 1439 if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) { 1440 smallScreen = -1; 1441 } else { 1442 smallScreen = 0; 1443 } 1444 if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) { 1445 normalScreen = -1; 1446 } else { 1447 normalScreen = 0; 1448 } 1449 if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) { 1450 largeScreen = -1; 1451 } else { 1452 largeScreen = 0; 1453 } 1454 if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) { 1455 xlargeScreen = -1; 1456 } else { 1457 xlargeScreen = 0; 1458 } 1459 } 1460 1461 // Determine default values for any unspecified screen sizes, 1462 // based on the target SDK of the package. As of 4 (donut) 1463 // the screen size support was introduced, so all default to 1464 // enabled. 1465 if (smallScreen > 0) { 1466 smallScreen = targetSdk >= 4 ? -1 : 0; 1467 } 1468 if (normalScreen > 0) { 1469 normalScreen = -1; 1470 } 1471 if (largeScreen > 0) { 1472 largeScreen = targetSdk >= 4 ? -1 : 0; 1473 } 1474 if (xlargeScreen > 0) { 1475 // Introduced in Gingerbread. 1476 xlargeScreen = targetSdk >= 9 ? -1 : 0; 1477 } 1478 if (anyDensity > 0) { 1479 anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0 1480 || compatibleWidthLimitDp > 0) ? -1 : 0; 1481 } 1482 printf("supports-screens:"); 1483 if (smallScreen != 0) printf(" 'small'"); 1484 if (normalScreen != 0) printf(" 'normal'"); 1485 if (largeScreen != 0) printf(" 'large'"); 1486 if (xlargeScreen != 0) printf(" 'xlarge'"); 1487 printf("\n"); 1488 printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false"); 1489 if (requiresSmallestWidthDp > 0) { 1490 printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp); 1491 } 1492 if (compatibleWidthLimitDp > 0) { 1493 printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp); 1494 } 1495 if (largestWidthLimitDp > 0) { 1496 printf("largest-width-limit:'%d'\n", largestWidthLimitDp); 1497 } 1498 1499 printf("locales:"); 1500 const size_t NL = locales.size(); 1501 for (size_t i=0; i<NL; i++) { 1502 const char* localeStr = locales[i].string(); 1503 if (localeStr == NULL || strlen(localeStr) == 0) { 1504 localeStr = "--_--"; 1505 } 1506 printf(" '%s'", localeStr); 1507 } 1508 printf("\n"); 1509 1510 printf("densities:"); 1511 const size_t ND = densities.size(); 1512 for (size_t i=0; i<ND; i++) { 1513 printf(" '%d'", densities[i]); 1514 } 1515 printf("\n"); 1516 1517 AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib"); 1518 if (dir != NULL) { 1519 if (dir->getFileCount() > 0) { 1520 printf("native-code:"); 1521 for (size_t i=0; i<dir->getFileCount(); i++) { 1522 printf(" '%s'", dir->getFileName(i).string()); 1523 } 1524 printf("\n"); 1525 } 1526 delete dir; 1527 } 1528 } else if (strcmp("badger", option) == 0) { 1529 printf("%s", CONSOLE_DATA); 1530 } else if (strcmp("configurations", option) == 0) { 1531 Vector<ResTable_config> configs; 1532 res.getConfigurations(&configs); 1533 const size_t N = configs.size(); 1534 for (size_t i=0; i<N; i++) { 1535 printf("%s\n", configs[i].toString().string()); 1536 } 1537 } else { 1538 fprintf(stderr, "ERROR: unknown dump option '%s'\n", option); 1539 goto bail; 1540 } 1541 } 1542 1543 result = NO_ERROR; 1544 1545bail: 1546 if (asset) { 1547 delete asset; 1548 } 1549 return (result != NO_ERROR); 1550} 1551 1552 1553/* 1554 * Handle the "add" command, which wants to add files to a new or 1555 * pre-existing archive. 1556 */ 1557int doAdd(Bundle* bundle) 1558{ 1559 ZipFile* zip = NULL; 1560 status_t result = UNKNOWN_ERROR; 1561 const char* zipFileName; 1562 1563 if (bundle->getUpdate()) { 1564 /* avoid confusion */ 1565 fprintf(stderr, "ERROR: can't use '-u' with add\n"); 1566 goto bail; 1567 } 1568 1569 if (bundle->getFileSpecCount() < 1) { 1570 fprintf(stderr, "ERROR: must specify zip file name\n"); 1571 goto bail; 1572 } 1573 zipFileName = bundle->getFileSpecEntry(0); 1574 1575 if (bundle->getFileSpecCount() < 2) { 1576 fprintf(stderr, "NOTE: nothing to do\n"); 1577 goto bail; 1578 } 1579 1580 zip = openReadWrite(zipFileName, true); 1581 if (zip == NULL) { 1582 fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName); 1583 goto bail; 1584 } 1585 1586 for (int i = 1; i < bundle->getFileSpecCount(); i++) { 1587 const char* fileName = bundle->getFileSpecEntry(i); 1588 1589 if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) { 1590 printf(" '%s'... (from gzip)\n", fileName); 1591 result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL); 1592 } else { 1593 if (bundle->getJunkPath()) { 1594 String8 storageName = String8(fileName).getPathLeaf(); 1595 printf(" '%s' as '%s'...\n", fileName, storageName.string()); 1596 result = zip->add(fileName, storageName.string(), 1597 bundle->getCompressionMethod(), NULL); 1598 } else { 1599 printf(" '%s'...\n", fileName); 1600 result = zip->add(fileName, bundle->getCompressionMethod(), NULL); 1601 } 1602 } 1603 if (result != NO_ERROR) { 1604 fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName); 1605 if (result == NAME_NOT_FOUND) 1606 fprintf(stderr, ": file not found\n"); 1607 else if (result == ALREADY_EXISTS) 1608 fprintf(stderr, ": already exists in archive\n"); 1609 else 1610 fprintf(stderr, "\n"); 1611 goto bail; 1612 } 1613 } 1614 1615 result = NO_ERROR; 1616 1617bail: 1618 delete zip; 1619 return (result != NO_ERROR); 1620} 1621 1622 1623/* 1624 * Delete files from an existing archive. 1625 */ 1626int doRemove(Bundle* bundle) 1627{ 1628 ZipFile* zip = NULL; 1629 status_t result = UNKNOWN_ERROR; 1630 const char* zipFileName; 1631 1632 if (bundle->getFileSpecCount() < 1) { 1633 fprintf(stderr, "ERROR: must specify zip file name\n"); 1634 goto bail; 1635 } 1636 zipFileName = bundle->getFileSpecEntry(0); 1637 1638 if (bundle->getFileSpecCount() < 2) { 1639 fprintf(stderr, "NOTE: nothing to do\n"); 1640 goto bail; 1641 } 1642 1643 zip = openReadWrite(zipFileName, false); 1644 if (zip == NULL) { 1645 fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n", 1646 zipFileName); 1647 goto bail; 1648 } 1649 1650 for (int i = 1; i < bundle->getFileSpecCount(); i++) { 1651 const char* fileName = bundle->getFileSpecEntry(i); 1652 ZipEntry* entry; 1653 1654 entry = zip->getEntryByName(fileName); 1655 if (entry == NULL) { 1656 printf(" '%s' NOT FOUND\n", fileName); 1657 continue; 1658 } 1659 1660 result = zip->remove(entry); 1661 1662 if (result != NO_ERROR) { 1663 fprintf(stderr, "Unable to delete '%s' from '%s'\n", 1664 bundle->getFileSpecEntry(i), zipFileName); 1665 goto bail; 1666 } 1667 } 1668 1669 /* update the archive */ 1670 zip->flush(); 1671 1672bail: 1673 delete zip; 1674 return (result != NO_ERROR); 1675} 1676 1677 1678/* 1679 * Package up an asset directory and associated application files. 1680 */ 1681int doPackage(Bundle* bundle) 1682{ 1683 const char* outputAPKFile; 1684 int retVal = 1; 1685 status_t err; 1686 sp<AaptAssets> assets; 1687 int N; 1688 FILE* fp; 1689 String8 dependencyFile; 1690 1691 // -c zz_ZZ means do pseudolocalization 1692 ResourceFilter filter; 1693 err = filter.parse(bundle->getConfigurations()); 1694 if (err != NO_ERROR) { 1695 goto bail; 1696 } 1697 if (filter.containsPseudo()) { 1698 bundle->setPseudolocalize(true); 1699 } 1700 1701 N = bundle->getFileSpecCount(); 1702 if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0 1703 && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) { 1704 fprintf(stderr, "ERROR: no input files\n"); 1705 goto bail; 1706 } 1707 1708 outputAPKFile = bundle->getOutputAPKFile(); 1709 1710 // Make sure the filenames provided exist and are of the appropriate type. 1711 if (outputAPKFile) { 1712 FileType type; 1713 type = getFileType(outputAPKFile); 1714 if (type != kFileTypeNonexistent && type != kFileTypeRegular) { 1715 fprintf(stderr, 1716 "ERROR: output file '%s' exists but is not regular file\n", 1717 outputAPKFile); 1718 goto bail; 1719 } 1720 } 1721 1722 // Load the assets. 1723 assets = new AaptAssets(); 1724 1725 // Set up the resource gathering in assets if we're going to generate 1726 // dependency files. Every time we encounter a resource while slurping 1727 // the tree, we'll add it to these stores so we have full resource paths 1728 // to write to a dependency file. 1729 if (bundle->getGenDependencies()) { 1730 sp<FilePathStore> resPathStore = new FilePathStore; 1731 assets->setFullResPaths(resPathStore); 1732 sp<FilePathStore> assetPathStore = new FilePathStore; 1733 assets->setFullAssetPaths(assetPathStore); 1734 } 1735 1736 err = assets->slurpFromArgs(bundle); 1737 if (err < 0) { 1738 goto bail; 1739 } 1740 1741 if (bundle->getVerbose()) { 1742 assets->print(String8()); 1743 } 1744 1745 // If they asked for any fileAs that need to be compiled, do so. 1746 if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) { 1747 err = buildResources(bundle, assets); 1748 if (err != 0) { 1749 goto bail; 1750 } 1751 } 1752 1753 // At this point we've read everything and processed everything. From here 1754 // on out it's just writing output files. 1755 if (SourcePos::hasErrors()) { 1756 goto bail; 1757 } 1758 1759 // Update symbols with information about which ones are needed as Java symbols. 1760 assets->applyJavaSymbols(); 1761 if (SourcePos::hasErrors()) { 1762 goto bail; 1763 } 1764 1765 // If we've been asked to generate a dependency file, do that here 1766 if (bundle->getGenDependencies()) { 1767 // If this is the packaging step, generate the dependency file next to 1768 // the output apk (e.g. bin/resources.ap_.d) 1769 if (outputAPKFile) { 1770 dependencyFile = String8(outputAPKFile); 1771 // Add the .d extension to the dependency file. 1772 dependencyFile.append(".d"); 1773 } else { 1774 // Else if this is the R.java dependency generation step, 1775 // generate the dependency file in the R.java package subdirectory 1776 // e.g. gen/com/foo/app/R.java.d 1777 dependencyFile = String8(bundle->getRClassDir()); 1778 dependencyFile.appendPath("R.java.d"); 1779 } 1780 // Make sure we have a clean dependency file to start with 1781 fp = fopen(dependencyFile, "w"); 1782 fclose(fp); 1783 } 1784 1785 // Write out R.java constants 1786 if (!assets->havePrivateSymbols()) { 1787 if (bundle->getCustomPackage() == NULL) { 1788 // Write the R.java file into the appropriate class directory 1789 // e.g. gen/com/foo/app/R.java 1790 err = writeResourceSymbols(bundle, assets, assets->getPackage(), true); 1791 } else { 1792 const String8 customPkg(bundle->getCustomPackage()); 1793 err = writeResourceSymbols(bundle, assets, customPkg, true); 1794 } 1795 if (err < 0) { 1796 goto bail; 1797 } 1798 // If we have library files, we're going to write our R.java file into 1799 // the appropriate class directory for those libraries as well. 1800 // e.g. gen/com/foo/app/lib/R.java 1801 if (bundle->getExtraPackages() != NULL) { 1802 // Split on colon 1803 String8 libs(bundle->getExtraPackages()); 1804 char* packageString = strtok(libs.lockBuffer(libs.length()), ":"); 1805 while (packageString != NULL) { 1806 // Write the R.java file out with the correct package name 1807 err = writeResourceSymbols(bundle, assets, String8(packageString), true); 1808 if (err < 0) { 1809 goto bail; 1810 } 1811 packageString = strtok(NULL, ":"); 1812 } 1813 libs.unlockBuffer(); 1814 } 1815 } else { 1816 err = writeResourceSymbols(bundle, assets, assets->getPackage(), false); 1817 if (err < 0) { 1818 goto bail; 1819 } 1820 err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true); 1821 if (err < 0) { 1822 goto bail; 1823 } 1824 } 1825 1826 // Write out the ProGuard file 1827 err = writeProguardFile(bundle, assets); 1828 if (err < 0) { 1829 goto bail; 1830 } 1831 1832 // Write the apk 1833 if (outputAPKFile) { 1834 err = writeAPK(bundle, assets, String8(outputAPKFile)); 1835 if (err != NO_ERROR) { 1836 fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputAPKFile); 1837 goto bail; 1838 } 1839 } 1840 1841 // If we've been asked to generate a dependency file, we need to finish up here. 1842 // the writeResourceSymbols and writeAPK functions have already written the target 1843 // half of the dependency file, now we need to write the prerequisites. (files that 1844 // the R.java file or .ap_ file depend on) 1845 if (bundle->getGenDependencies()) { 1846 // Now that writeResourceSymbols or writeAPK has taken care of writing 1847 // the targets to our dependency file, we'll write the prereqs 1848 fp = fopen(dependencyFile, "a+"); 1849 fprintf(fp, " : "); 1850 bool includeRaw = (outputAPKFile != NULL); 1851 err = writeDependencyPreReqs(bundle, assets, fp, includeRaw); 1852 // Also manually add the AndroidManifeset since it's not under res/ or assets/ 1853 // and therefore was not added to our pathstores during slurping 1854 fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile()); 1855 fclose(fp); 1856 } 1857 1858 retVal = 0; 1859bail: 1860 if (SourcePos::hasErrors()) { 1861 SourcePos::printErrors(stderr); 1862 } 1863 return retVal; 1864} 1865 1866/* 1867 * Do PNG Crunching 1868 * PRECONDITIONS 1869 * -S flag points to a source directory containing drawable* folders 1870 * -C flag points to destination directory. The folder structure in the 1871 * source directory will be mirrored to the destination (cache) directory 1872 * 1873 * POSTCONDITIONS 1874 * Destination directory will be updated to match the PNG files in 1875 * the source directory. 1876 */ 1877int doCrunch(Bundle* bundle) 1878{ 1879 fprintf(stdout, "Crunching PNG Files in "); 1880 fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]); 1881 fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir()); 1882 1883 updatePreProcessedCache(bundle); 1884 1885 return NO_ERROR; 1886} 1887 1888/* 1889 * Do PNG Crunching on a single flag 1890 * -i points to a single png file 1891 * -o points to a single png output file 1892 */ 1893int doSingleCrunch(Bundle* bundle) 1894{ 1895 fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile()); 1896 fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile()); 1897 1898 String8 input(bundle->getSingleCrunchInputFile()); 1899 String8 output(bundle->getSingleCrunchOutputFile()); 1900 1901 if (preProcessImageToCache(bundle, input, output) != NO_ERROR) { 1902 // we can't return the status_t as it gets truncate to the lower 8 bits. 1903 return 42; 1904 } 1905 1906 return NO_ERROR; 1907} 1908 1909char CONSOLE_DATA[2925] = { 1910 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1911 32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1912 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1913 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 1914 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63, 1915 86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83, 1916 62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1917 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1918 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81, 1919 81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32, 1920 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 1921 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1922 32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59, 1923 59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1924 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1925 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 1926 59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32, 1927 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1928 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1929 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87, 1930 58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32, 1931 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 1932 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 1933 47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58, 1934 121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1935 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1936 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81, 1937 81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32, 1938 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 1939 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1940 32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59, 1941 59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1942 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1943 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59, 1944 59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32, 1945 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1946 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1947 32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81, 1948 70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 1949 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 1950 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1951 32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81, 1952 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1953 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1954 32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109, 1955 81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32, 1956 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 1957 32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59, 1958 59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59, 1959 60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1960 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59, 1961 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46, 1962 61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32, 1963 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1964 32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 1965 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81, 1966 109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32, 1967 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81, 1968 67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 1969 59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58, 1970 61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32, 1971 32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59, 1972 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37, 1973 73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59, 1974 59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 1975 32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59, 1976 59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96, 1977 46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 1978 97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32, 1979 46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61, 1980 119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59, 1981 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32, 1982 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1983 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119, 1984 119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 1985 59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10, 1986 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1987 32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81, 1988 81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41, 1989 87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 1990 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81, 1991 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 1992 45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32, 1993 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1994 32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 1995 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 1996 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 1997 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 1998 59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 1999 59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2000 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2001 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81, 2002 81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32, 2003 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2004 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2005 32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2006 81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2007 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 2008 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106, 2009 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59, 2010 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2011 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2012 32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81, 2013 81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 2014 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 2015 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2016 58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59, 2017 61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2018 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2019 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81, 2020 81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32, 2021 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2022 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2023 32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2024 81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2025 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 2026 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 2027 59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59, 2028 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2029 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2030 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33, 2031 58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 2032 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 2033 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 2034 61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59, 2035 59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 2036 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 2037 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95, 2038 32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59, 2039 61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2040 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2041 32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45, 2042 59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32, 2043 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 2044 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59, 2045 59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59, 2046 59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2047 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2048 32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, 2049 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32, 2050 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 2051 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2052 46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61, 2053 46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2054 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 2055 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 2056 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59, 2057 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2058 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2059 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32, 2060 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32, 2061 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 2062 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61, 2063 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 2064 59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2065 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2066 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32, 2067 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32, 2068 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2069 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2070 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2071 32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2072 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10 2073 }; 2074