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