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