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