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