Command.cpp revision eb8d1be6acad180eabde84f19196b9ecaba81353
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 bool hasDreamService = false; 823 824 bool actMainActivity = false; 825 bool actWidgetReceivers = false; 826 bool actDeviceAdminEnabled = false; 827 bool actImeService = false; 828 bool actWallpaperService = false; 829 bool actAccessibilityService = false; 830 bool actPrintService = false; 831 bool actHostApduService = false; 832 bool actOffHostApduService = false; 833 bool actDocumentsProvider = false; 834 bool actNotificationListenerService = false; 835 bool actDreamService = false; 836 bool actCamera = false; 837 bool actCameraSecure = false; 838 bool catLauncher = false; 839 bool hasMetaHostPaymentCategory = false; 840 bool hasMetaOffHostPaymentCategory = false; 841 842 // These permissions are required by services implementing services 843 // the system binds to (IME, Accessibility, PrintServices, etc.) 844 bool hasBindDeviceAdminPermission = false; 845 bool hasBindInputMethodPermission = false; 846 bool hasBindAccessibilityServicePermission = false; 847 bool hasBindPrintServicePermission = false; 848 bool hasBindNfcServicePermission = false; 849 bool hasRequiredSafAttributes = false; 850 bool hasBindNotificationListenerServicePermission = false; 851 bool hasBindDreamServicePermission = false; 852 853 // These two implement the implicit permissions that are granted 854 // to pre-1.6 applications. 855 bool hasWriteExternalStoragePermission = false; 856 bool hasReadPhoneStatePermission = false; 857 858 // If an app requests write storage, they will also get read storage. 859 bool hasReadExternalStoragePermission = false; 860 861 // Implement transition to read and write call log. 862 bool hasReadContactsPermission = false; 863 bool hasWriteContactsPermission = false; 864 bool hasReadCallLogPermission = false; 865 bool hasWriteCallLogPermission = false; 866 867 // This next group of variables is used to implement a group of 868 // backward-compatibility heuristics necessitated by the addition of 869 // some new uses-feature constants in 2.1 and 2.2. In most cases, the 870 // heuristic is "if an app requests a permission but doesn't explicitly 871 // request the corresponding <uses-feature>, presume it's there anyway". 872 bool specCameraFeature = false; // camera-related 873 bool specCameraAutofocusFeature = false; 874 bool reqCameraAutofocusFeature = false; 875 bool reqCameraFlashFeature = false; 876 bool hasCameraPermission = false; 877 bool specLocationFeature = false; // location-related 878 bool specNetworkLocFeature = false; 879 bool reqNetworkLocFeature = false; 880 bool specGpsFeature = false; 881 bool reqGpsFeature = false; 882 bool hasMockLocPermission = false; 883 bool hasCoarseLocPermission = false; 884 bool hasGpsPermission = false; 885 bool hasGeneralLocPermission = false; 886 bool specBluetoothFeature = false; // Bluetooth API-related 887 bool hasBluetoothPermission = false; 888 bool specMicrophoneFeature = false; // microphone-related 889 bool hasRecordAudioPermission = false; 890 bool specWiFiFeature = false; 891 bool hasWiFiPermission = false; 892 bool specTelephonyFeature = false; // telephony-related 893 bool reqTelephonySubFeature = false; 894 bool hasTelephonyPermission = false; 895 bool specTouchscreenFeature = false; // touchscreen-related 896 bool specMultitouchFeature = false; 897 bool reqDistinctMultitouchFeature = false; 898 bool specScreenPortraitFeature = false; 899 bool specScreenLandscapeFeature = false; 900 bool reqScreenPortraitFeature = false; 901 bool reqScreenLandscapeFeature = false; 902 // 2.2 also added some other features that apps can request, but that 903 // have no corresponding permission, so we cannot implement any 904 // back-compatibility heuristic for them. The below are thus unnecessary 905 // (but are retained here for documentary purposes.) 906 //bool specCompassFeature = false; 907 //bool specAccelerometerFeature = false; 908 //bool specProximityFeature = false; 909 //bool specAmbientLightFeature = false; 910 //bool specLiveWallpaperFeature = false; 911 912 int targetSdk = 0; 913 int smallScreen = 1; 914 int normalScreen = 1; 915 int largeScreen = 1; 916 int xlargeScreen = 1; 917 int anyDensity = 1; 918 int requiresSmallestWidthDp = 0; 919 int compatibleWidthLimitDp = 0; 920 int largestWidthLimitDp = 0; 921 String8 pkg; 922 String8 activityName; 923 String8 activityLabel; 924 String8 activityIcon; 925 String8 activityBanner; 926 String8 receiverName; 927 String8 serviceName; 928 Vector<String8> supportedInput; 929 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { 930 if (code == ResXMLTree::END_TAG) { 931 depth--; 932 if (depth < 2) { 933 if (withinSupportsInput && !supportedInput.isEmpty()) { 934 printf("supports-input: '"); 935 const size_t N = supportedInput.size(); 936 for (size_t i=0; i<N; i++) { 937 printf("%s", ResTable::normalizeForOutput( 938 supportedInput[i].string()).string()); 939 if (i != N - 1) { 940 printf("' '"); 941 } else { 942 printf("'\n"); 943 } 944 } 945 supportedInput.clear(); 946 } 947 withinApplication = false; 948 withinSupportsInput = false; 949 } else if (depth < 3) { 950 if (withinActivity && isMainActivity) { 951 String8 aName(getComponentName(pkg, activityName)); 952 if (isLauncherActivity) { 953 printf("launchable-activity:"); 954 if (aName.length() > 0) { 955 printf(" name='%s' ", 956 ResTable::normalizeForOutput(aName.string()).string()); 957 } 958 printf(" label='%s' icon='%s'\n", 959 ResTable::normalizeForOutput(activityLabel.string()).string(), 960 ResTable::normalizeForOutput(activityIcon.string()).string()); 961 } 962 if (isLeanbackLauncherActivity) { 963 printf("leanback-launchable-activity:"); 964 if (aName.length() > 0) { 965 printf(" name='%s' ", 966 ResTable::normalizeForOutput(aName.string()).string()); 967 } 968 printf(" label='%s' icon='%s' banner='%s'\n", 969 ResTable::normalizeForOutput(activityLabel.string()).string(), 970 ResTable::normalizeForOutput(activityIcon.string()).string(), 971 ResTable::normalizeForOutput(activityBanner.string()).string()); 972 } 973 } 974 if (!hasIntentFilter) { 975 hasOtherActivities |= withinActivity; 976 hasOtherReceivers |= withinReceiver; 977 hasOtherServices |= withinService; 978 } else { 979 if (withinService) { 980 hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory && 981 hasBindNfcServicePermission); 982 hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory && 983 hasBindNfcServicePermission); 984 } 985 } 986 withinActivity = false; 987 withinService = false; 988 withinReceiver = false; 989 withinProvider = false; 990 hasIntentFilter = false; 991 isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false; 992 } else if (depth < 4) { 993 if (withinIntentFilter) { 994 if (withinActivity) { 995 hasMainActivity |= actMainActivity; 996 hasLauncher |= catLauncher; 997 hasCameraActivity |= actCamera; 998 hasCameraSecureActivity |= actCameraSecure; 999 hasOtherActivities |= !actMainActivity && !actCamera && !actCameraSecure; 1000 } else if (withinReceiver) { 1001 hasWidgetReceivers |= actWidgetReceivers; 1002 hasDeviceAdminReceiver |= (actDeviceAdminEnabled && 1003 hasBindDeviceAdminPermission); 1004 hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled); 1005 } else if (withinService) { 1006 hasImeService |= actImeService; 1007 hasWallpaperService |= actWallpaperService; 1008 hasAccessibilityService |= (actAccessibilityService && 1009 hasBindAccessibilityServicePermission); 1010 hasPrintService |= (actPrintService && hasBindPrintServicePermission); 1011 hasNotificationListenerService |= actNotificationListenerService && 1012 hasBindNotificationListenerServicePermission; 1013 hasDreamService |= actDreamService && hasBindDreamServicePermission; 1014 hasOtherServices |= (!actImeService && !actWallpaperService && 1015 !actAccessibilityService && !actPrintService && 1016 !actHostApduService && !actOffHostApduService && 1017 !actNotificationListenerService); 1018 } else if (withinProvider) { 1019 hasDocumentsProvider |= actDocumentsProvider && hasRequiredSafAttributes; 1020 } 1021 } 1022 withinIntentFilter = false; 1023 } 1024 continue; 1025 } 1026 if (code != ResXMLTree::START_TAG) { 1027 continue; 1028 } 1029 depth++; 1030 1031 const char16_t* ctag16 = tree.getElementName(&len); 1032 if (ctag16 == NULL) { 1033 fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n"); 1034 goto bail; 1035 } 1036 String8 tag(ctag16); 1037 //printf("Depth %d, %s\n", depth, tag.string()); 1038 if (depth == 1) { 1039 if (tag != "manifest") { 1040 fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); 1041 goto bail; 1042 } 1043 pkg = getAttribute(tree, NULL, "package", NULL); 1044 printf("package: name='%s' ", 1045 ResTable::normalizeForOutput(pkg.string()).string()); 1046 int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error); 1047 if (error != "") { 1048 fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string()); 1049 goto bail; 1050 } 1051 if (versionCode > 0) { 1052 printf("versionCode='%d' ", versionCode); 1053 } else { 1054 printf("versionCode='' "); 1055 } 1056 String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error); 1057 if (error != "") { 1058 fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string()); 1059 goto bail; 1060 } 1061 printf("versionName='%s'\n", 1062 ResTable::normalizeForOutput(versionName.string()).string()); 1063 } else if (depth == 2) { 1064 withinApplication = false; 1065 if (tag == "application") { 1066 withinApplication = true; 1067 1068 String8 label; 1069 const size_t NL = locales.size(); 1070 for (size_t i=0; i<NL; i++) { 1071 const char* localeStr = locales[i].string(); 1072 assets.setLocale(localeStr != NULL ? localeStr : ""); 1073 String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); 1074 if (llabel != "") { 1075 if (localeStr == NULL || strlen(localeStr) == 0) { 1076 label = llabel; 1077 printf("application-label:'%s'\n", 1078 ResTable::normalizeForOutput(llabel.string()).string()); 1079 } else { 1080 if (label == "") { 1081 label = llabel; 1082 } 1083 printf("application-label-%s:'%s'\n", localeStr, 1084 ResTable::normalizeForOutput(llabel.string()).string()); 1085 } 1086 } 1087 } 1088 1089 ResTable_config tmpConfig = config; 1090 const size_t ND = densities.size(); 1091 for (size_t i=0; i<ND; i++) { 1092 tmpConfig.density = densities[i]; 1093 assets.setConfiguration(tmpConfig); 1094 String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 1095 if (icon != "") { 1096 printf("application-icon-%d:'%s'\n", densities[i], 1097 ResTable::normalizeForOutput(icon.string()).string()); 1098 } 1099 } 1100 assets.setConfiguration(config); 1101 1102 String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 1103 if (error != "") { 1104 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); 1105 goto bail; 1106 } 1107 int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0); 1108 if (error != "") { 1109 fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string()); 1110 goto bail; 1111 } 1112 printf("application: label='%s' ", 1113 ResTable::normalizeForOutput(label.string()).string()); 1114 printf("icon='%s'\n", ResTable::normalizeForOutput(icon.string()).string()); 1115 if (testOnly != 0) { 1116 printf("testOnly='%d'\n", testOnly); 1117 } 1118 1119 int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0); 1120 if (error != "") { 1121 fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string()); 1122 goto bail; 1123 } 1124 if (debuggable != 0) { 1125 printf("application-debuggable\n"); 1126 } 1127 } else if (tag == "uses-sdk") { 1128 int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error); 1129 if (error != "") { 1130 error = ""; 1131 String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error); 1132 if (error != "") { 1133 fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n", 1134 error.string()); 1135 goto bail; 1136 } 1137 if (name == "Donut") targetSdk = 4; 1138 printf("sdkVersion:'%s'\n", 1139 ResTable::normalizeForOutput(name.string()).string()); 1140 } else if (code != -1) { 1141 targetSdk = code; 1142 printf("sdkVersion:'%d'\n", code); 1143 } 1144 code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1); 1145 if (code != -1) { 1146 printf("maxSdkVersion:'%d'\n", code); 1147 } 1148 code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error); 1149 if (error != "") { 1150 error = ""; 1151 String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error); 1152 if (error != "") { 1153 fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n", 1154 error.string()); 1155 goto bail; 1156 } 1157 if (name == "Donut" && targetSdk < 4) targetSdk = 4; 1158 printf("targetSdkVersion:'%s'\n", 1159 ResTable::normalizeForOutput(name.string()).string()); 1160 } else if (code != -1) { 1161 if (targetSdk < code) { 1162 targetSdk = code; 1163 } 1164 printf("targetSdkVersion:'%d'\n", code); 1165 } 1166 } else if (tag == "uses-configuration") { 1167 int32_t reqTouchScreen = getIntegerAttribute(tree, 1168 REQ_TOUCH_SCREEN_ATTR, NULL, 0); 1169 int32_t reqKeyboardType = getIntegerAttribute(tree, 1170 REQ_KEYBOARD_TYPE_ATTR, NULL, 0); 1171 int32_t reqHardKeyboard = getIntegerAttribute(tree, 1172 REQ_HARD_KEYBOARD_ATTR, NULL, 0); 1173 int32_t reqNavigation = getIntegerAttribute(tree, 1174 REQ_NAVIGATION_ATTR, NULL, 0); 1175 int32_t reqFiveWayNav = getIntegerAttribute(tree, 1176 REQ_FIVE_WAY_NAV_ATTR, NULL, 0); 1177 printf("uses-configuration:"); 1178 if (reqTouchScreen != 0) { 1179 printf(" reqTouchScreen='%d'", reqTouchScreen); 1180 } 1181 if (reqKeyboardType != 0) { 1182 printf(" reqKeyboardType='%d'", reqKeyboardType); 1183 } 1184 if (reqHardKeyboard != 0) { 1185 printf(" reqHardKeyboard='%d'", reqHardKeyboard); 1186 } 1187 if (reqNavigation != 0) { 1188 printf(" reqNavigation='%d'", reqNavigation); 1189 } 1190 if (reqFiveWayNav != 0) { 1191 printf(" reqFiveWayNav='%d'", reqFiveWayNav); 1192 } 1193 printf("\n"); 1194 } else if (tag == "supports-input") { 1195 withinSupportsInput = true; 1196 } else if (tag == "supports-screens") { 1197 smallScreen = getIntegerAttribute(tree, 1198 SMALL_SCREEN_ATTR, NULL, 1); 1199 normalScreen = getIntegerAttribute(tree, 1200 NORMAL_SCREEN_ATTR, NULL, 1); 1201 largeScreen = getIntegerAttribute(tree, 1202 LARGE_SCREEN_ATTR, NULL, 1); 1203 xlargeScreen = getIntegerAttribute(tree, 1204 XLARGE_SCREEN_ATTR, NULL, 1); 1205 anyDensity = getIntegerAttribute(tree, 1206 ANY_DENSITY_ATTR, NULL, 1); 1207 requiresSmallestWidthDp = getIntegerAttribute(tree, 1208 REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0); 1209 compatibleWidthLimitDp = getIntegerAttribute(tree, 1210 COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0); 1211 largestWidthLimitDp = getIntegerAttribute(tree, 1212 LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0); 1213 } else if (tag == "uses-feature") { 1214 String8 name = getAttribute(tree, NAME_ATTR, &error); 1215 1216 if (name != "" && error == "") { 1217 int req = getIntegerAttribute(tree, 1218 REQUIRED_ATTR, NULL, 1); 1219 1220 if (name == "android.hardware.camera") { 1221 specCameraFeature = true; 1222 } else if (name == "android.hardware.camera.autofocus") { 1223 // these have no corresponding permission to check for, 1224 // but should imply the foundational camera permission 1225 reqCameraAutofocusFeature = reqCameraAutofocusFeature || req; 1226 specCameraAutofocusFeature = true; 1227 } else if (req && (name == "android.hardware.camera.flash")) { 1228 // these have no corresponding permission to check for, 1229 // but should imply the foundational camera permission 1230 reqCameraFlashFeature = true; 1231 } else if (name == "android.hardware.location") { 1232 specLocationFeature = true; 1233 } else if (name == "android.hardware.location.network") { 1234 specNetworkLocFeature = true; 1235 reqNetworkLocFeature = reqNetworkLocFeature || req; 1236 } else if (name == "android.hardware.location.gps") { 1237 specGpsFeature = true; 1238 reqGpsFeature = reqGpsFeature || req; 1239 } else if (name == "android.hardware.bluetooth") { 1240 specBluetoothFeature = true; 1241 } else if (name == "android.hardware.touchscreen") { 1242 specTouchscreenFeature = true; 1243 } else if (name == "android.hardware.touchscreen.multitouch") { 1244 specMultitouchFeature = true; 1245 } else if (name == "android.hardware.touchscreen.multitouch.distinct") { 1246 reqDistinctMultitouchFeature = reqDistinctMultitouchFeature || req; 1247 } else if (name == "android.hardware.microphone") { 1248 specMicrophoneFeature = true; 1249 } else if (name == "android.hardware.wifi") { 1250 specWiFiFeature = true; 1251 } else if (name == "android.hardware.telephony") { 1252 specTelephonyFeature = true; 1253 } else if (req && (name == "android.hardware.telephony.gsm" || 1254 name == "android.hardware.telephony.cdma")) { 1255 // these have no corresponding permission to check for, 1256 // but should imply the foundational telephony permission 1257 reqTelephonySubFeature = true; 1258 } else if (name == "android.hardware.screen.portrait") { 1259 specScreenPortraitFeature = true; 1260 } else if (name == "android.hardware.screen.landscape") { 1261 specScreenLandscapeFeature = true; 1262 } 1263 printf("uses-feature%s:'%s'\n", 1264 req ? "" : "-not-required", 1265 ResTable::normalizeForOutput(name.string()).string()); 1266 } else { 1267 int vers = getIntegerAttribute(tree, 1268 GL_ES_VERSION_ATTR, &error); 1269 if (error == "") { 1270 printf("uses-gl-es:'0x%x'\n", vers); 1271 } 1272 } 1273 } else if (tag == "uses-permission") { 1274 String8 name = getAttribute(tree, NAME_ATTR, &error); 1275 if (name != "" && error == "") { 1276 if (name == "android.permission.CAMERA") { 1277 hasCameraPermission = true; 1278 } else if (name == "android.permission.ACCESS_FINE_LOCATION") { 1279 hasGpsPermission = true; 1280 } else if (name == "android.permission.ACCESS_MOCK_LOCATION") { 1281 hasMockLocPermission = true; 1282 } else if (name == "android.permission.ACCESS_COARSE_LOCATION") { 1283 hasCoarseLocPermission = true; 1284 } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" || 1285 name == "android.permission.INSTALL_LOCATION_PROVIDER") { 1286 hasGeneralLocPermission = true; 1287 } else if (name == "android.permission.BLUETOOTH" || 1288 name == "android.permission.BLUETOOTH_ADMIN") { 1289 hasBluetoothPermission = true; 1290 } else if (name == "android.permission.RECORD_AUDIO") { 1291 hasRecordAudioPermission = true; 1292 } else if (name == "android.permission.ACCESS_WIFI_STATE" || 1293 name == "android.permission.CHANGE_WIFI_STATE" || 1294 name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") { 1295 hasWiFiPermission = true; 1296 } else if (name == "android.permission.CALL_PHONE" || 1297 name == "android.permission.CALL_PRIVILEGED" || 1298 name == "android.permission.MODIFY_PHONE_STATE" || 1299 name == "android.permission.PROCESS_OUTGOING_CALLS" || 1300 name == "android.permission.READ_SMS" || 1301 name == "android.permission.RECEIVE_SMS" || 1302 name == "android.permission.RECEIVE_MMS" || 1303 name == "android.permission.RECEIVE_WAP_PUSH" || 1304 name == "android.permission.SEND_SMS" || 1305 name == "android.permission.WRITE_APN_SETTINGS" || 1306 name == "android.permission.WRITE_SMS") { 1307 hasTelephonyPermission = true; 1308 } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") { 1309 hasWriteExternalStoragePermission = true; 1310 } else if (name == "android.permission.READ_EXTERNAL_STORAGE") { 1311 hasReadExternalStoragePermission = true; 1312 } else if (name == "android.permission.READ_PHONE_STATE") { 1313 hasReadPhoneStatePermission = true; 1314 } else if (name == "android.permission.READ_CONTACTS") { 1315 hasReadContactsPermission = true; 1316 } else if (name == "android.permission.WRITE_CONTACTS") { 1317 hasWriteContactsPermission = true; 1318 } else if (name == "android.permission.READ_CALL_LOG") { 1319 hasReadCallLogPermission = true; 1320 } else if (name == "android.permission.WRITE_CALL_LOG") { 1321 hasWriteCallLogPermission = true; 1322 } 1323 1324 printUsesPermission(name, 1325 getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0, 1326 getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1)); 1327 } else { 1328 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1329 error.string()); 1330 goto bail; 1331 } 1332 } else if (tag == "uses-package") { 1333 String8 name = getAttribute(tree, NAME_ATTR, &error); 1334 if (name != "" && error == "") { 1335 printf("uses-package:'%s'\n", 1336 ResTable::normalizeForOutput(name.string()).string()); 1337 } else { 1338 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1339 error.string()); 1340 goto bail; 1341 } 1342 } else if (tag == "original-package") { 1343 String8 name = getAttribute(tree, NAME_ATTR, &error); 1344 if (name != "" && error == "") { 1345 printf("original-package:'%s'\n", 1346 ResTable::normalizeForOutput(name.string()).string()); 1347 } else { 1348 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1349 error.string()); 1350 goto bail; 1351 } 1352 } else if (tag == "supports-gl-texture") { 1353 String8 name = getAttribute(tree, NAME_ATTR, &error); 1354 if (name != "" && error == "") { 1355 printf("supports-gl-texture:'%s'\n", 1356 ResTable::normalizeForOutput(name.string()).string()); 1357 } else { 1358 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1359 error.string()); 1360 goto bail; 1361 } 1362 } else if (tag == "compatible-screens") { 1363 printCompatibleScreens(tree, &error); 1364 if (error != "") { 1365 fprintf(stderr, "ERROR getting compatible screens: %s\n", 1366 error.string()); 1367 goto bail; 1368 } 1369 depth--; 1370 } else if (tag == "package-verifier") { 1371 String8 name = getAttribute(tree, NAME_ATTR, &error); 1372 if (name != "" && error == "") { 1373 String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error); 1374 if (publicKey != "" && error == "") { 1375 printf("package-verifier: name='%s' publicKey='%s'\n", 1376 ResTable::normalizeForOutput(name.string()).string(), 1377 ResTable::normalizeForOutput(publicKey.string()).string()); 1378 } 1379 } 1380 } 1381 } else if (depth == 3) { 1382 withinActivity = false; 1383 withinReceiver = false; 1384 withinService = false; 1385 withinProvider = false; 1386 hasIntentFilter = false; 1387 hasMetaHostPaymentCategory = false; 1388 hasMetaOffHostPaymentCategory = false; 1389 hasBindDeviceAdminPermission = false; 1390 hasBindInputMethodPermission = false; 1391 hasBindAccessibilityServicePermission = false; 1392 hasBindPrintServicePermission = false; 1393 hasBindNfcServicePermission = false; 1394 hasRequiredSafAttributes = false; 1395 hasBindNotificationListenerServicePermission = false; 1396 hasBindDreamServicePermission = false; 1397 if (withinApplication) { 1398 if(tag == "activity") { 1399 withinActivity = true; 1400 activityName = getAttribute(tree, NAME_ATTR, &error); 1401 if (error != "") { 1402 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1403 error.string()); 1404 goto bail; 1405 } 1406 1407 activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); 1408 if (error != "") { 1409 fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", 1410 error.string()); 1411 goto bail; 1412 } 1413 1414 activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 1415 if (error != "") { 1416 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", 1417 error.string()); 1418 goto bail; 1419 } 1420 1421 activityBanner = getResolvedAttribute(&res, tree, BANNER_ATTR, &error); 1422 if (error != "") { 1423 fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n", 1424 error.string()); 1425 goto bail; 1426 } 1427 1428 int32_t orien = getResolvedIntegerAttribute(&res, tree, 1429 SCREEN_ORIENTATION_ATTR, &error); 1430 if (error == "") { 1431 if (orien == 0 || orien == 6 || orien == 8) { 1432 // Requests landscape, sensorLandscape, or reverseLandscape. 1433 reqScreenLandscapeFeature = true; 1434 } else if (orien == 1 || orien == 7 || orien == 9) { 1435 // Requests portrait, sensorPortrait, or reversePortrait. 1436 reqScreenPortraitFeature = true; 1437 } 1438 } 1439 } else if (tag == "uses-library") { 1440 String8 libraryName = getAttribute(tree, NAME_ATTR, &error); 1441 if (error != "") { 1442 fprintf(stderr, 1443 "ERROR getting 'android:name' attribute for uses-library" 1444 " %s\n", error.string()); 1445 goto bail; 1446 } 1447 int req = getIntegerAttribute(tree, 1448 REQUIRED_ATTR, NULL, 1); 1449 printf("uses-library%s:'%s'\n", 1450 req ? "" : "-not-required", ResTable::normalizeForOutput( 1451 libraryName.string()).string()); 1452 } else if (tag == "receiver") { 1453 withinReceiver = true; 1454 receiverName = getAttribute(tree, NAME_ATTR, &error); 1455 1456 if (error != "") { 1457 fprintf(stderr, 1458 "ERROR getting 'android:name' attribute for receiver:" 1459 " %s\n", error.string()); 1460 goto bail; 1461 } 1462 1463 String8 permission = getAttribute(tree, PERMISSION_ATTR, &error); 1464 if (error == "") { 1465 if (permission == "android.permission.BIND_DEVICE_ADMIN") { 1466 hasBindDeviceAdminPermission = true; 1467 } 1468 } else { 1469 fprintf(stderr, "ERROR getting 'android:permission' attribute for" 1470 " receiver '%s': %s\n", receiverName.string(), error.string()); 1471 } 1472 } else if (tag == "service") { 1473 withinService = true; 1474 serviceName = getAttribute(tree, NAME_ATTR, &error); 1475 1476 if (error != "") { 1477 fprintf(stderr, "ERROR getting 'android:name' attribute for " 1478 "service:%s\n", error.string()); 1479 goto bail; 1480 } 1481 1482 String8 permission = getAttribute(tree, PERMISSION_ATTR, &error); 1483 if (error == "") { 1484 if (permission == "android.permission.BIND_INPUT_METHOD") { 1485 hasBindInputMethodPermission = true; 1486 } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") { 1487 hasBindAccessibilityServicePermission = true; 1488 } else if (permission == "android.permission.BIND_PRINT_SERVICE") { 1489 hasBindPrintServicePermission = true; 1490 } else if (permission == "android.permission.BIND_NFC_SERVICE") { 1491 hasBindNfcServicePermission = true; 1492 } else if (permission == "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") { 1493 hasBindNotificationListenerServicePermission = true; 1494 } else if (permission == "android.permission.BIND_DREAM_SERVICE") { 1495 hasBindDreamServicePermission = true; 1496 } 1497 } else { 1498 fprintf(stderr, "ERROR getting 'android:permission' attribute for" 1499 " service '%s': %s\n", serviceName.string(), error.string()); 1500 } 1501 } else if (tag == "provider") { 1502 withinProvider = true; 1503 1504 bool exported = getResolvedIntegerAttribute(&res, tree, EXPORTED_ATTR, &error); 1505 if (error != "") { 1506 fprintf(stderr, "ERROR getting 'android:exported' attribute for provider:" 1507 " %s\n", error.string()); 1508 goto bail; 1509 } 1510 1511 bool grantUriPermissions = getResolvedIntegerAttribute(&res, tree, 1512 GRANT_URI_PERMISSIONS_ATTR, &error); 1513 if (error != "") { 1514 fprintf(stderr, "ERROR getting 'android:grantUriPermissions' attribute for provider:" 1515 " %s\n", error.string()); 1516 goto bail; 1517 } 1518 1519 String8 permission = getResolvedAttribute(&res, tree, PERMISSION_ATTR, &error); 1520 if (error != "") { 1521 fprintf(stderr, "ERROR getting 'android:permission' attribute for provider:" 1522 " %s\n", error.string()); 1523 goto bail; 1524 } 1525 1526 hasRequiredSafAttributes |= exported && grantUriPermissions && 1527 permission == "android.permission.MANAGE_DOCUMENTS"; 1528 1529 } else if (bundle->getIncludeMetaData() && tag == "meta-data") { 1530 String8 metaDataName = getResolvedAttribute(&res, tree, NAME_ATTR, &error); 1531 if (error != "") { 1532 fprintf(stderr, "ERROR getting 'android:name' attribute for " 1533 "meta-data:%s\n", error.string()); 1534 goto bail; 1535 } 1536 printf("meta-data: name='%s' ", 1537 ResTable::normalizeForOutput(metaDataName.string()).string()); 1538 printResolvedResourceAttribute(&res, tree, VALUE_ATTR, String8("value"), 1539 &error); 1540 if (error != "") { 1541 // Try looking for a RESOURCE_ATTR 1542 error = ""; 1543 printResolvedResourceAttribute(&res, tree, RESOURCE_ATTR, 1544 String8("resource"), &error); 1545 if (error != "") { 1546 fprintf(stderr, "ERROR getting 'android:value' or " 1547 "'android:resource' attribute for " 1548 "meta-data:%s\n", error.string()); 1549 goto bail; 1550 } 1551 } 1552 printf("\n"); 1553 } else if (withinSupportsInput && tag == "input-type") { 1554 String8 name = getAttribute(tree, NAME_ATTR, &error); 1555 if (name != "" && error == "") { 1556 supportedInput.add(name); 1557 } else { 1558 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1559 error.string()); 1560 goto bail; 1561 } 1562 } 1563 } 1564 } else if (depth == 4) { 1565 if (tag == "intent-filter") { 1566 hasIntentFilter = true; 1567 withinIntentFilter = true; 1568 actMainActivity = false; 1569 actWidgetReceivers = false; 1570 actImeService = false; 1571 actWallpaperService = false; 1572 actAccessibilityService = false; 1573 actPrintService = false; 1574 actDeviceAdminEnabled = false; 1575 actHostApduService = false; 1576 actOffHostApduService = false; 1577 actDocumentsProvider = false; 1578 actNotificationListenerService = false; 1579 actDreamService = false; 1580 actCamera = false; 1581 actCameraSecure = false; 1582 catLauncher = false; 1583 } else if (withinService && tag == "meta-data") { 1584 String8 name = getAttribute(tree, NAME_ATTR, &error); 1585 if (error != "") { 1586 fprintf(stderr, "ERROR getting 'android:name' attribute for" 1587 " meta-data tag in service '%s': %s\n", serviceName.string(), error.string()); 1588 goto bail; 1589 } 1590 1591 if (name == "android.nfc.cardemulation.host_apdu_service" || 1592 name == "android.nfc.cardemulation.off_host_apdu_service") { 1593 bool offHost = true; 1594 if (name == "android.nfc.cardemulation.host_apdu_service") { 1595 offHost = false; 1596 } 1597 1598 String8 xmlPath = getResolvedAttribute(&res, tree, RESOURCE_ATTR, &error); 1599 if (error != "") { 1600 fprintf(stderr, "ERROR getting 'android:resource' attribute for" 1601 " meta-data tag in service '%s': %s\n", serviceName.string(), error.string()); 1602 goto bail; 1603 } 1604 1605 Vector<String8> categories = getNfcAidCategories(assets, xmlPath, 1606 offHost, &error); 1607 if (error != "") { 1608 fprintf(stderr, "ERROR getting AID category for service '%s'\n", 1609 serviceName.string()); 1610 goto bail; 1611 } 1612 1613 const size_t catLen = categories.size(); 1614 for (size_t i = 0; i < catLen; i++) { 1615 bool paymentCategory = (categories[i] == "payment"); 1616 if (offHost) { 1617 hasMetaOffHostPaymentCategory |= paymentCategory; 1618 } else { 1619 hasMetaHostPaymentCategory |= paymentCategory; 1620 } 1621 } 1622 } 1623 } 1624 } else if ((depth == 5) && withinIntentFilter) { 1625 String8 action; 1626 if (tag == "action") { 1627 action = getAttribute(tree, NAME_ATTR, &error); 1628 if (error != "") { 1629 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1630 error.string()); 1631 goto bail; 1632 } 1633 1634 if (withinActivity) { 1635 if (action == "android.intent.action.MAIN") { 1636 isMainActivity = true; 1637 actMainActivity = true; 1638 } else if (action == "android.media.action.STILL_IMAGE_CAMERA" || 1639 action == "android.media.action.VIDEO_CAMERA") { 1640 actCamera = true; 1641 } else if (action == "android.media.action.STILL_IMAGE_CAMERA_SECURE") { 1642 actCameraSecure = true; 1643 } 1644 } else if (withinReceiver) { 1645 if (action == "android.appwidget.action.APPWIDGET_UPDATE") { 1646 actWidgetReceivers = true; 1647 } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") { 1648 actDeviceAdminEnabled = true; 1649 } 1650 } else if (withinService) { 1651 if (action == "android.view.InputMethod") { 1652 actImeService = true; 1653 } else if (action == "android.service.wallpaper.WallpaperService") { 1654 actWallpaperService = true; 1655 } else if (action == "android.accessibilityservice.AccessibilityService") { 1656 actAccessibilityService = true; 1657 } else if (action == "android.printservice.PrintService") { 1658 actPrintService = true; 1659 } else if (action == "android.nfc.cardemulation.action.HOST_APDU_SERVICE") { 1660 actHostApduService = true; 1661 } else if (action == "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") { 1662 actOffHostApduService = true; 1663 } else if (action == "android.service.notification.NotificationListenerService") { 1664 actNotificationListenerService = true; 1665 } else if (action == "android.service.dreams.DreamService") { 1666 actDreamService = true; 1667 } 1668 } else if (withinProvider) { 1669 if (action == "android.content.action.DOCUMENTS_PROVIDER") { 1670 actDocumentsProvider = true; 1671 } 1672 } 1673 if (action == "android.intent.action.SEARCH") { 1674 isSearchable = true; 1675 } 1676 } 1677 1678 if (tag == "category") { 1679 String8 category = getAttribute(tree, NAME_ATTR, &error); 1680 if (error != "") { 1681 fprintf(stderr, "ERROR getting 'name' attribute: %s\n", 1682 error.string()); 1683 goto bail; 1684 } 1685 if (withinActivity) { 1686 if (category == "android.intent.category.LAUNCHER") { 1687 isLauncherActivity = true; 1688 } else if (category == "android.intent.category.LEANBACK_LAUNCHER") { 1689 isLeanbackLauncherActivity = true; 1690 } else if (category == "android.intent.category.HOME") { 1691 catLauncher = true; 1692 } 1693 } 1694 } 1695 } 1696 } 1697 1698 // Pre-1.6 implicitly granted permission compatibility logic 1699 if (targetSdk < 4) { 1700 if (!hasWriteExternalStoragePermission) { 1701 printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE")); 1702 printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"), 1703 String8("targetSdkVersion < 4")); 1704 hasWriteExternalStoragePermission = true; 1705 } 1706 if (!hasReadPhoneStatePermission) { 1707 printUsesPermission(String8("android.permission.READ_PHONE_STATE")); 1708 printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"), 1709 String8("targetSdkVersion < 4")); 1710 } 1711 } 1712 1713 // If the application has requested WRITE_EXTERNAL_STORAGE, we will 1714 // force them to always take READ_EXTERNAL_STORAGE as well. We always 1715 // do this (regardless of target API version) because we can't have 1716 // an app with write permission but not read permission. 1717 if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) { 1718 printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE")); 1719 printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"), 1720 String8("requested WRITE_EXTERNAL_STORAGE")); 1721 } 1722 1723 // Pre-JellyBean call log permission compatibility. 1724 if (targetSdk < 16) { 1725 if (!hasReadCallLogPermission && hasReadContactsPermission) { 1726 printUsesPermission(String8("android.permission.READ_CALL_LOG")); 1727 printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"), 1728 String8("targetSdkVersion < 16 and requested READ_CONTACTS")); 1729 } 1730 if (!hasWriteCallLogPermission && hasWriteContactsPermission) { 1731 printUsesPermission(String8("android.permission.WRITE_CALL_LOG")); 1732 printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"), 1733 String8("targetSdkVersion < 16 and requested WRITE_CONTACTS")); 1734 } 1735 } 1736 1737 /* The following blocks handle printing "inferred" uses-features, based 1738 * on whether related features or permissions are used by the app. 1739 * Note that the various spec*Feature variables denote whether the 1740 * relevant tag was *present* in the AndroidManfest, not that it was 1741 * present and set to true. 1742 */ 1743 // Camera-related back-compatibility logic 1744 if (!specCameraFeature) { 1745 if (reqCameraFlashFeature) { 1746 // if app requested a sub-feature (autofocus or flash) and didn't 1747 // request the base camera feature, we infer that it meant to 1748 printf("uses-feature:'android.hardware.camera'\n"); 1749 printf("uses-implied-feature:'android.hardware.camera'," \ 1750 "'requested android.hardware.camera.flash feature'\n"); 1751 } else if (reqCameraAutofocusFeature) { 1752 // if app requested a sub-feature (autofocus or flash) and didn't 1753 // request the base camera feature, we infer that it meant to 1754 printf("uses-feature:'android.hardware.camera'\n"); 1755 printf("uses-implied-feature:'android.hardware.camera'," \ 1756 "'requested android.hardware.camera.autofocus feature'\n"); 1757 } else if (hasCameraPermission) { 1758 // if app wants to use camera but didn't request the feature, we infer 1759 // that it meant to, and further that it wants autofocus 1760 // (which was the 1.0 - 1.5 behavior) 1761 printf("uses-feature:'android.hardware.camera'\n"); 1762 if (!specCameraAutofocusFeature) { 1763 printf("uses-feature:'android.hardware.camera.autofocus'\n"); 1764 printf("uses-implied-feature:'android.hardware.camera.autofocus'," \ 1765 "'requested android.permission.CAMERA permission'\n"); 1766 } 1767 } 1768 } 1769 1770 // Location-related back-compatibility logic 1771 if (!specLocationFeature && 1772 (hasMockLocPermission || hasCoarseLocPermission || hasGpsPermission || 1773 hasGeneralLocPermission || reqNetworkLocFeature || reqGpsFeature)) { 1774 // if app either takes a location-related permission or requests one of the 1775 // sub-features, we infer that it also meant to request the base location feature 1776 printf("uses-feature:'android.hardware.location'\n"); 1777 printf("uses-implied-feature:'android.hardware.location'," \ 1778 "'requested a location access permission'\n"); 1779 } 1780 if (!specGpsFeature && hasGpsPermission) { 1781 // if app takes GPS (FINE location) perm but does not request the GPS 1782 // feature, we infer that it meant to 1783 printf("uses-feature:'android.hardware.location.gps'\n"); 1784 printf("uses-implied-feature:'android.hardware.location.gps'," \ 1785 "'requested android.permission.ACCESS_FINE_LOCATION permission'\n"); 1786 } 1787 if (!specNetworkLocFeature && hasCoarseLocPermission) { 1788 // if app takes Network location (COARSE location) perm but does not request the 1789 // network location feature, we infer that it meant to 1790 printf("uses-feature:'android.hardware.location.network'\n"); 1791 printf("uses-implied-feature:'android.hardware.location.network'," \ 1792 "'requested android.permission.ACCESS_COARSE_LOCATION permission'\n"); 1793 } 1794 1795 // Bluetooth-related compatibility logic 1796 if (!specBluetoothFeature && hasBluetoothPermission && (targetSdk > 4)) { 1797 // if app takes a Bluetooth permission but does not request the Bluetooth 1798 // feature, we infer that it meant to 1799 printf("uses-feature:'android.hardware.bluetooth'\n"); 1800 printf("uses-implied-feature:'android.hardware.bluetooth'," \ 1801 "'requested android.permission.BLUETOOTH or android.permission.BLUETOOTH_ADMIN " \ 1802 "permission and targetSdkVersion > 4'\n"); 1803 } 1804 1805 // Microphone-related compatibility logic 1806 if (!specMicrophoneFeature && hasRecordAudioPermission) { 1807 // if app takes the record-audio permission but does not request the microphone 1808 // feature, we infer that it meant to 1809 printf("uses-feature:'android.hardware.microphone'\n"); 1810 printf("uses-implied-feature:'android.hardware.microphone'," \ 1811 "'requested android.permission.RECORD_AUDIO permission'\n"); 1812 } 1813 1814 // WiFi-related compatibility logic 1815 if (!specWiFiFeature && hasWiFiPermission) { 1816 // if app takes one of the WiFi permissions but does not request the WiFi 1817 // feature, we infer that it meant to 1818 printf("uses-feature:'android.hardware.wifi'\n"); 1819 printf("uses-implied-feature:'android.hardware.wifi'," \ 1820 "'requested android.permission.ACCESS_WIFI_STATE, " \ 1821 "android.permission.CHANGE_WIFI_STATE, or " \ 1822 "android.permission.CHANGE_WIFI_MULTICAST_STATE permission'\n"); 1823 } 1824 1825 // Telephony-related compatibility logic 1826 if (!specTelephonyFeature && (hasTelephonyPermission || reqTelephonySubFeature)) { 1827 // if app takes one of the telephony permissions or requests a sub-feature but 1828 // does not request the base telephony feature, we infer that it meant to 1829 printf("uses-feature:'android.hardware.telephony'\n"); 1830 printf("uses-implied-feature:'android.hardware.telephony'," \ 1831 "'requested a telephony-related permission or feature'\n"); 1832 } 1833 1834 // Touchscreen-related back-compatibility logic 1835 if (!specTouchscreenFeature) { // not a typo! 1836 // all apps are presumed to require a touchscreen, unless they explicitly say 1837 // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> 1838 // Note that specTouchscreenFeature is true if the tag is present, regardless 1839 // of whether its value is true or false, so this is safe 1840 printf("uses-feature:'android.hardware.touchscreen'\n"); 1841 printf("uses-implied-feature:'android.hardware.touchscreen'," \ 1842 "'assumed you require a touch screen unless explicitly made optional'\n"); 1843 } 1844 if (!specMultitouchFeature && reqDistinctMultitouchFeature) { 1845 // if app takes one of the telephony permissions or requests a sub-feature but 1846 // does not request the base telephony feature, we infer that it meant to 1847 printf("uses-feature:'android.hardware.touchscreen.multitouch'\n"); 1848 printf("uses-implied-feature:'android.hardware.touchscreen.multitouch'," \ 1849 "'requested android.hardware.touchscreen.multitouch.distinct feature'\n"); 1850 } 1851 1852 // Landscape/portrait-related compatibility logic 1853 if (!specScreenLandscapeFeature && !specScreenPortraitFeature) { 1854 // If the app has specified any activities in its manifest 1855 // that request a specific orientation, then assume that 1856 // orientation is required. 1857 if (reqScreenLandscapeFeature) { 1858 printf("uses-feature:'android.hardware.screen.landscape'\n"); 1859 printf("uses-implied-feature:'android.hardware.screen.landscape'," \ 1860 "'one or more activities have specified a landscape orientation'\n"); 1861 } 1862 if (reqScreenPortraitFeature) { 1863 printf("uses-feature:'android.hardware.screen.portrait'\n"); 1864 printf("uses-implied-feature:'android.hardware.screen.portrait'," \ 1865 "'one or more activities have specified a portrait orientation'\n"); 1866 } 1867 } 1868 1869 if (hasWidgetReceivers) { 1870 printComponentPresence("app-widget"); 1871 } 1872 if (hasDeviceAdminReceiver) { 1873 printComponentPresence("device-admin"); 1874 } 1875 if (hasImeService) { 1876 printComponentPresence("ime"); 1877 } 1878 if (hasWallpaperService) { 1879 printComponentPresence("wallpaper"); 1880 } 1881 if (hasAccessibilityService) { 1882 printComponentPresence("accessibility"); 1883 } 1884 if (hasPrintService) { 1885 printComponentPresence("print-service"); 1886 } 1887 if (hasPaymentService) { 1888 printComponentPresence("payment"); 1889 } 1890 if (isSearchable) { 1891 printComponentPresence("search"); 1892 } 1893 if (hasDocumentsProvider) { 1894 printComponentPresence("document-provider"); 1895 } 1896 if (hasLauncher) { 1897 printComponentPresence("launcher"); 1898 } 1899 if (hasNotificationListenerService) { 1900 printComponentPresence("notification-listener"); 1901 } 1902 if (hasDreamService) { 1903 printComponentPresence("dream"); 1904 } 1905 if (hasCameraActivity) { 1906 printComponentPresence("camera"); 1907 } 1908 if (hasCameraSecureActivity) { 1909 printComponentPresence("camera-secure"); 1910 } 1911 1912 if (hasMainActivity) { 1913 printf("main\n"); 1914 } 1915 if (hasOtherActivities) { 1916 printf("other-activities\n"); 1917 } 1918 if (hasOtherReceivers) { 1919 printf("other-receivers\n"); 1920 } 1921 if (hasOtherServices) { 1922 printf("other-services\n"); 1923 } 1924 1925 // For modern apps, if screen size buckets haven't been specified 1926 // but the new width ranges have, then infer the buckets from them. 1927 if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0 1928 && requiresSmallestWidthDp > 0) { 1929 int compatWidth = compatibleWidthLimitDp; 1930 if (compatWidth <= 0) { 1931 compatWidth = requiresSmallestWidthDp; 1932 } 1933 if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) { 1934 smallScreen = -1; 1935 } else { 1936 smallScreen = 0; 1937 } 1938 if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) { 1939 normalScreen = -1; 1940 } else { 1941 normalScreen = 0; 1942 } 1943 if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) { 1944 largeScreen = -1; 1945 } else { 1946 largeScreen = 0; 1947 } 1948 if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) { 1949 xlargeScreen = -1; 1950 } else { 1951 xlargeScreen = 0; 1952 } 1953 } 1954 1955 // Determine default values for any unspecified screen sizes, 1956 // based on the target SDK of the package. As of 4 (donut) 1957 // the screen size support was introduced, so all default to 1958 // enabled. 1959 if (smallScreen > 0) { 1960 smallScreen = targetSdk >= 4 ? -1 : 0; 1961 } 1962 if (normalScreen > 0) { 1963 normalScreen = -1; 1964 } 1965 if (largeScreen > 0) { 1966 largeScreen = targetSdk >= 4 ? -1 : 0; 1967 } 1968 if (xlargeScreen > 0) { 1969 // Introduced in Gingerbread. 1970 xlargeScreen = targetSdk >= 9 ? -1 : 0; 1971 } 1972 if (anyDensity > 0) { 1973 anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0 1974 || compatibleWidthLimitDp > 0) ? -1 : 0; 1975 } 1976 printf("supports-screens:"); 1977 if (smallScreen != 0) { 1978 printf(" 'small'"); 1979 } 1980 if (normalScreen != 0) { 1981 printf(" 'normal'"); 1982 } 1983 if (largeScreen != 0) { 1984 printf(" 'large'"); 1985 } 1986 if (xlargeScreen != 0) { 1987 printf(" 'xlarge'"); 1988 } 1989 printf("\n"); 1990 printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false"); 1991 if (requiresSmallestWidthDp > 0) { 1992 printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp); 1993 } 1994 if (compatibleWidthLimitDp > 0) { 1995 printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp); 1996 } 1997 if (largestWidthLimitDp > 0) { 1998 printf("largest-width-limit:'%d'\n", largestWidthLimitDp); 1999 } 2000 2001 printf("locales:"); 2002 const size_t NL = locales.size(); 2003 for (size_t i=0; i<NL; i++) { 2004 const char* localeStr = locales[i].string(); 2005 if (localeStr == NULL || strlen(localeStr) == 0) { 2006 localeStr = "--_--"; 2007 } 2008 printf(" '%s'", localeStr); 2009 } 2010 printf("\n"); 2011 2012 printf("densities:"); 2013 const size_t ND = densities.size(); 2014 for (size_t i=0; i<ND; i++) { 2015 printf(" '%d'", densities[i]); 2016 } 2017 printf("\n"); 2018 2019 AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib"); 2020 if (dir != NULL) { 2021 if (dir->getFileCount() > 0) { 2022 printf("native-code:"); 2023 for (size_t i=0; i<dir->getFileCount(); i++) { 2024 printf(" '%s'", ResTable::normalizeForOutput( 2025 dir->getFileName(i).string()).string()); 2026 } 2027 printf("\n"); 2028 } 2029 delete dir; 2030 } 2031 } else if (strcmp("badger", option) == 0) { 2032 printf("%s", CONSOLE_DATA); 2033 } else if (strcmp("configurations", option) == 0) { 2034 Vector<ResTable_config> configs; 2035 res.getConfigurations(&configs); 2036 const size_t N = configs.size(); 2037 for (size_t i=0; i<N; i++) { 2038 printf("%s\n", configs[i].toString().string()); 2039 } 2040 } else { 2041 fprintf(stderr, "ERROR: unknown dump option '%s'\n", option); 2042 goto bail; 2043 } 2044 } 2045 2046 result = NO_ERROR; 2047 2048bail: 2049 if (asset) { 2050 delete asset; 2051 } 2052 return (result != NO_ERROR); 2053} 2054 2055 2056/* 2057 * Handle the "add" command, which wants to add files to a new or 2058 * pre-existing archive. 2059 */ 2060int doAdd(Bundle* bundle) 2061{ 2062 ZipFile* zip = NULL; 2063 status_t result = UNKNOWN_ERROR; 2064 const char* zipFileName; 2065 2066 if (bundle->getUpdate()) { 2067 /* avoid confusion */ 2068 fprintf(stderr, "ERROR: can't use '-u' with add\n"); 2069 goto bail; 2070 } 2071 2072 if (bundle->getFileSpecCount() < 1) { 2073 fprintf(stderr, "ERROR: must specify zip file name\n"); 2074 goto bail; 2075 } 2076 zipFileName = bundle->getFileSpecEntry(0); 2077 2078 if (bundle->getFileSpecCount() < 2) { 2079 fprintf(stderr, "NOTE: nothing to do\n"); 2080 goto bail; 2081 } 2082 2083 zip = openReadWrite(zipFileName, true); 2084 if (zip == NULL) { 2085 fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName); 2086 goto bail; 2087 } 2088 2089 for (int i = 1; i < bundle->getFileSpecCount(); i++) { 2090 const char* fileName = bundle->getFileSpecEntry(i); 2091 2092 if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) { 2093 printf(" '%s'... (from gzip)\n", fileName); 2094 result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL); 2095 } else { 2096 if (bundle->getJunkPath()) { 2097 String8 storageName = String8(fileName).getPathLeaf(); 2098 printf(" '%s' as '%s'...\n", fileName, 2099 ResTable::normalizeForOutput(storageName.string()).string()); 2100 result = zip->add(fileName, storageName.string(), 2101 bundle->getCompressionMethod(), NULL); 2102 } else { 2103 printf(" '%s'...\n", fileName); 2104 result = zip->add(fileName, bundle->getCompressionMethod(), NULL); 2105 } 2106 } 2107 if (result != NO_ERROR) { 2108 fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName); 2109 if (result == NAME_NOT_FOUND) { 2110 fprintf(stderr, ": file not found\n"); 2111 } else if (result == ALREADY_EXISTS) { 2112 fprintf(stderr, ": already exists in archive\n"); 2113 } else { 2114 fprintf(stderr, "\n"); 2115 } 2116 goto bail; 2117 } 2118 } 2119 2120 result = NO_ERROR; 2121 2122bail: 2123 delete zip; 2124 return (result != NO_ERROR); 2125} 2126 2127 2128/* 2129 * Delete files from an existing archive. 2130 */ 2131int doRemove(Bundle* bundle) 2132{ 2133 ZipFile* zip = NULL; 2134 status_t result = UNKNOWN_ERROR; 2135 const char* zipFileName; 2136 2137 if (bundle->getFileSpecCount() < 1) { 2138 fprintf(stderr, "ERROR: must specify zip file name\n"); 2139 goto bail; 2140 } 2141 zipFileName = bundle->getFileSpecEntry(0); 2142 2143 if (bundle->getFileSpecCount() < 2) { 2144 fprintf(stderr, "NOTE: nothing to do\n"); 2145 goto bail; 2146 } 2147 2148 zip = openReadWrite(zipFileName, false); 2149 if (zip == NULL) { 2150 fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n", 2151 zipFileName); 2152 goto bail; 2153 } 2154 2155 for (int i = 1; i < bundle->getFileSpecCount(); i++) { 2156 const char* fileName = bundle->getFileSpecEntry(i); 2157 ZipEntry* entry; 2158 2159 entry = zip->getEntryByName(fileName); 2160 if (entry == NULL) { 2161 printf(" '%s' NOT FOUND\n", fileName); 2162 continue; 2163 } 2164 2165 result = zip->remove(entry); 2166 2167 if (result != NO_ERROR) { 2168 fprintf(stderr, "Unable to delete '%s' from '%s'\n", 2169 bundle->getFileSpecEntry(i), zipFileName); 2170 goto bail; 2171 } 2172 } 2173 2174 /* update the archive */ 2175 zip->flush(); 2176 2177bail: 2178 delete zip; 2179 return (result != NO_ERROR); 2180} 2181 2182static status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) { 2183 const size_t numDirs = dir->getDirs().size(); 2184 for (size_t i = 0; i < numDirs; i++) { 2185 bool ignore = ignoreConfig; 2186 const sp<AaptDir>& subDir = dir->getDirs().valueAt(i); 2187 const char* dirStr = subDir->getLeaf().string(); 2188 if (!ignore && strstr(dirStr, "mipmap") == dirStr) { 2189 ignore = true; 2190 } 2191 status_t err = addResourcesToBuilder(subDir, builder, ignore); 2192 if (err != NO_ERROR) { 2193 return err; 2194 } 2195 } 2196 2197 const size_t numFiles = dir->getFiles().size(); 2198 for (size_t i = 0; i < numFiles; i++) { 2199 sp<AaptGroup> gp = dir->getFiles().valueAt(i); 2200 const size_t numConfigs = gp->getFiles().size(); 2201 for (size_t j = 0; j < numConfigs; j++) { 2202 status_t err = NO_ERROR; 2203 if (ignoreConfig) { 2204 err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j)); 2205 } else { 2206 err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j)); 2207 } 2208 if (err != NO_ERROR) { 2209 fprintf(stderr, "Failed to add %s (%s) to builder.\n", 2210 gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string()); 2211 return err; 2212 } 2213 } 2214 } 2215 return NO_ERROR; 2216} 2217 2218static String8 buildApkName(const String8& original, const sp<ApkSplit>& split) { 2219 if (split->isBase()) { 2220 return original; 2221 } 2222 2223 String8 ext(original.getPathExtension()); 2224 if (ext == String8(".apk")) { 2225 return String8::format("%s_%s%s", 2226 original.getBasePath().string(), 2227 split->getDirectorySafeName().string(), 2228 ext.string()); 2229 } 2230 2231 return String8::format("%s_%s", original.string(), 2232 split->getDirectorySafeName().string()); 2233} 2234 2235/* 2236 * Package up an asset directory and associated application files. 2237 */ 2238int doPackage(Bundle* bundle) 2239{ 2240 const char* outputAPKFile; 2241 int retVal = 1; 2242 status_t err; 2243 sp<AaptAssets> assets; 2244 int N; 2245 FILE* fp; 2246 String8 dependencyFile; 2247 sp<ApkBuilder> builder; 2248 2249 // -c en_XA or/and ar_XB means do pseudolocalization 2250 sp<WeakResourceFilter> configFilter = new WeakResourceFilter(); 2251 err = configFilter->parse(bundle->getConfigurations()); 2252 if (err != NO_ERROR) { 2253 goto bail; 2254 } 2255 if (configFilter->containsPseudo()) { 2256 bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED); 2257 } 2258 if (configFilter->containsPseudoBidi()) { 2259 bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI); 2260 } 2261 2262 N = bundle->getFileSpecCount(); 2263 if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0 2264 && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) { 2265 fprintf(stderr, "ERROR: no input files\n"); 2266 goto bail; 2267 } 2268 2269 outputAPKFile = bundle->getOutputAPKFile(); 2270 2271 // Make sure the filenames provided exist and are of the appropriate type. 2272 if (outputAPKFile) { 2273 FileType type; 2274 type = getFileType(outputAPKFile); 2275 if (type != kFileTypeNonexistent && type != kFileTypeRegular) { 2276 fprintf(stderr, 2277 "ERROR: output file '%s' exists but is not regular file\n", 2278 outputAPKFile); 2279 goto bail; 2280 } 2281 } 2282 2283 // Load the assets. 2284 assets = new AaptAssets(); 2285 2286 // Set up the resource gathering in assets if we're going to generate 2287 // dependency files. Every time we encounter a resource while slurping 2288 // the tree, we'll add it to these stores so we have full resource paths 2289 // to write to a dependency file. 2290 if (bundle->getGenDependencies()) { 2291 sp<FilePathStore> resPathStore = new FilePathStore; 2292 assets->setFullResPaths(resPathStore); 2293 sp<FilePathStore> assetPathStore = new FilePathStore; 2294 assets->setFullAssetPaths(assetPathStore); 2295 } 2296 2297 err = assets->slurpFromArgs(bundle); 2298 if (err < 0) { 2299 goto bail; 2300 } 2301 2302 if (bundle->getVerbose()) { 2303 assets->print(String8()); 2304 } 2305 2306 // Create the ApkBuilder, which will collect the compiled files 2307 // to write to the final APK (or sets of APKs if we are building 2308 // a Split APK. 2309 builder = new ApkBuilder(configFilter); 2310 2311 // If we are generating a Split APK, find out which configurations to split on. 2312 if (bundle->getSplitConfigurations().size() > 0) { 2313 const Vector<String8>& splitStrs = bundle->getSplitConfigurations(); 2314 const size_t numSplits = splitStrs.size(); 2315 for (size_t i = 0; i < numSplits; i++) { 2316 std::set<ConfigDescription> configs; 2317 if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) { 2318 fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string()); 2319 goto bail; 2320 } 2321 2322 err = builder->createSplitForConfigs(configs); 2323 if (err != NO_ERROR) { 2324 goto bail; 2325 } 2326 } 2327 } 2328 2329 // If they asked for any fileAs that need to be compiled, do so. 2330 if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) { 2331 err = buildResources(bundle, assets, builder); 2332 if (err != 0) { 2333 goto bail; 2334 } 2335 } 2336 2337 // At this point we've read everything and processed everything. From here 2338 // on out it's just writing output files. 2339 if (SourcePos::hasErrors()) { 2340 goto bail; 2341 } 2342 2343 // Update symbols with information about which ones are needed as Java symbols. 2344 assets->applyJavaSymbols(); 2345 if (SourcePos::hasErrors()) { 2346 goto bail; 2347 } 2348 2349 // If we've been asked to generate a dependency file, do that here 2350 if (bundle->getGenDependencies()) { 2351 // If this is the packaging step, generate the dependency file next to 2352 // the output apk (e.g. bin/resources.ap_.d) 2353 if (outputAPKFile) { 2354 dependencyFile = String8(outputAPKFile); 2355 // Add the .d extension to the dependency file. 2356 dependencyFile.append(".d"); 2357 } else { 2358 // Else if this is the R.java dependency generation step, 2359 // generate the dependency file in the R.java package subdirectory 2360 // e.g. gen/com/foo/app/R.java.d 2361 dependencyFile = String8(bundle->getRClassDir()); 2362 dependencyFile.appendPath("R.java.d"); 2363 } 2364 // Make sure we have a clean dependency file to start with 2365 fp = fopen(dependencyFile, "w"); 2366 fclose(fp); 2367 } 2368 2369 // Write out R.java constants 2370 if (!assets->havePrivateSymbols()) { 2371 if (bundle->getCustomPackage() == NULL) { 2372 // Write the R.java file into the appropriate class directory 2373 // e.g. gen/com/foo/app/R.java 2374 err = writeResourceSymbols(bundle, assets, assets->getPackage(), true); 2375 } else { 2376 const String8 customPkg(bundle->getCustomPackage()); 2377 err = writeResourceSymbols(bundle, assets, customPkg, true); 2378 } 2379 if (err < 0) { 2380 goto bail; 2381 } 2382 // If we have library files, we're going to write our R.java file into 2383 // the appropriate class directory for those libraries as well. 2384 // e.g. gen/com/foo/app/lib/R.java 2385 if (bundle->getExtraPackages() != NULL) { 2386 // Split on colon 2387 String8 libs(bundle->getExtraPackages()); 2388 char* packageString = strtok(libs.lockBuffer(libs.length()), ":"); 2389 while (packageString != NULL) { 2390 // Write the R.java file out with the correct package name 2391 err = writeResourceSymbols(bundle, assets, String8(packageString), true); 2392 if (err < 0) { 2393 goto bail; 2394 } 2395 packageString = strtok(NULL, ":"); 2396 } 2397 libs.unlockBuffer(); 2398 } 2399 } else { 2400 err = writeResourceSymbols(bundle, assets, assets->getPackage(), false); 2401 if (err < 0) { 2402 goto bail; 2403 } 2404 err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true); 2405 if (err < 0) { 2406 goto bail; 2407 } 2408 } 2409 2410 // Write out the ProGuard file 2411 err = writeProguardFile(bundle, assets); 2412 if (err < 0) { 2413 goto bail; 2414 } 2415 2416 // Write the apk 2417 if (outputAPKFile) { 2418 // Gather all resources and add them to the APK Builder. The builder will then 2419 // figure out which Split they belong in. 2420 err = addResourcesToBuilder(assets, builder); 2421 if (err != NO_ERROR) { 2422 goto bail; 2423 } 2424 2425 const Vector<sp<ApkSplit> >& splits = builder->getSplits(); 2426 const size_t numSplits = splits.size(); 2427 for (size_t i = 0; i < numSplits; i++) { 2428 const sp<ApkSplit>& split = splits[i]; 2429 String8 outputPath = buildApkName(String8(outputAPKFile), split); 2430 err = writeAPK(bundle, outputPath, split); 2431 if (err != NO_ERROR) { 2432 fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string()); 2433 goto bail; 2434 } 2435 } 2436 } 2437 2438 // If we've been asked to generate a dependency file, we need to finish up here. 2439 // the writeResourceSymbols and writeAPK functions have already written the target 2440 // half of the dependency file, now we need to write the prerequisites. (files that 2441 // the R.java file or .ap_ file depend on) 2442 if (bundle->getGenDependencies()) { 2443 // Now that writeResourceSymbols or writeAPK has taken care of writing 2444 // the targets to our dependency file, we'll write the prereqs 2445 fp = fopen(dependencyFile, "a+"); 2446 fprintf(fp, " : "); 2447 bool includeRaw = (outputAPKFile != NULL); 2448 err = writeDependencyPreReqs(bundle, assets, fp, includeRaw); 2449 // Also manually add the AndroidManifeset since it's not under res/ or assets/ 2450 // and therefore was not added to our pathstores during slurping 2451 fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile()); 2452 fclose(fp); 2453 } 2454 2455 retVal = 0; 2456bail: 2457 if (SourcePos::hasErrors()) { 2458 SourcePos::printErrors(stderr); 2459 } 2460 return retVal; 2461} 2462 2463/* 2464 * Do PNG Crunching 2465 * PRECONDITIONS 2466 * -S flag points to a source directory containing drawable* folders 2467 * -C flag points to destination directory. The folder structure in the 2468 * source directory will be mirrored to the destination (cache) directory 2469 * 2470 * POSTCONDITIONS 2471 * Destination directory will be updated to match the PNG files in 2472 * the source directory. 2473 */ 2474int doCrunch(Bundle* bundle) 2475{ 2476 fprintf(stdout, "Crunching PNG Files in "); 2477 fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]); 2478 fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir()); 2479 2480 updatePreProcessedCache(bundle); 2481 2482 return NO_ERROR; 2483} 2484 2485/* 2486 * Do PNG Crunching on a single flag 2487 * -i points to a single png file 2488 * -o points to a single png output file 2489 */ 2490int doSingleCrunch(Bundle* bundle) 2491{ 2492 fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile()); 2493 fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile()); 2494 2495 String8 input(bundle->getSingleCrunchInputFile()); 2496 String8 output(bundle->getSingleCrunchOutputFile()); 2497 2498 if (preProcessImageToCache(bundle, input, output) != NO_ERROR) { 2499 // we can't return the status_t as it gets truncate to the lower 8 bits. 2500 return 42; 2501 } 2502 2503 return NO_ERROR; 2504} 2505 2506char CONSOLE_DATA[2925] = { 2507 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2508 32, 32, 32, 32, 32, 32, 32, 95, 46, 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, 32, 32, 32, 2510 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 2511 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63, 2512 86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83, 2513 62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2514 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2515 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81, 2516 81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32, 2517 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 2518 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2519 32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59, 2520 59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2521 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2522 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 2523 59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32, 2524 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2525 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2526 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87, 2527 58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32, 2528 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 2529 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 2530 47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58, 2531 121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2532 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2533 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81, 2534 81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32, 2535 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 2536 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2537 32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59, 2538 59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2539 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2540 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59, 2541 59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32, 2542 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2543 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2544 32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81, 2545 70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 2546 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 2547 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2548 32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81, 2549 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2550 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2551 32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109, 2552 81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32, 2553 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 2554 32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59, 2555 59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59, 2556 60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2557 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59, 2558 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46, 2559 61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32, 2560 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2561 32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 2562 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81, 2563 109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32, 2564 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81, 2565 67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2566 59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58, 2567 61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32, 2568 32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59, 2569 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37, 2570 73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59, 2571 59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 2572 32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59, 2573 59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96, 2574 46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 2575 97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32, 2576 46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61, 2577 119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59, 2578 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32, 2579 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2580 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119, 2581 119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2582 59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10, 2583 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2584 32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81, 2585 81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41, 2586 87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 2587 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81, 2588 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 2589 45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32, 2590 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2591 32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 2592 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 2593 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 2594 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 2595 59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 2596 59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2597 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2598 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81, 2599 81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32, 2600 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2601 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2602 32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2603 81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2604 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 2605 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106, 2606 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59, 2607 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2608 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2609 32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81, 2610 81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 2611 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 2612 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2613 58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59, 2614 61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2615 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2616 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81, 2617 81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32, 2618 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2619 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2620 32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2621 81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2622 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 2623 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 2624 59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59, 2625 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2626 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2627 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33, 2628 58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 2629 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 2630 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 2631 61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59, 2632 59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 2633 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 2634 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95, 2635 32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59, 2636 61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2637 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2638 32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45, 2639 59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32, 2640 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 2641 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59, 2642 59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59, 2643 59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2644 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2645 32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, 2646 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32, 2647 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 2648 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2649 46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61, 2650 46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2651 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 2652 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 2653 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59, 2654 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2655 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2656 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32, 2657 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32, 2658 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 2659 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61, 2660 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 2661 59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2662 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2663 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32, 2664 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32, 2665 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2666 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2667 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2668 32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2669 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10 2670 }; 2671