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