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