Command.cpp revision e17086ba346009a26cc2299b133a0fe602acb6ec
1// 2// Copyright 2006 The Android Open Source Project 3// 4// Android Asset Packaging Tool main entry point. 5// 6#include "Main.h" 7#include "Bundle.h" 8#include "ResourceTable.h" 9#include "XMLNode.h" 10 11#include <utils.h> 12#include <utils/ZipFile.h> 13 14#include <fcntl.h> 15#include <errno.h> 16 17using namespace android; 18 19/* 20 * Show version info. All the cool kids do it. 21 */ 22int doVersion(Bundle* bundle) 23{ 24 if (bundle->getFileSpecCount() != 0) 25 printf("(ignoring extra arguments)\n"); 26 printf("Android Asset Packaging Tool, v0.2\n"); 27 28 return 0; 29} 30 31 32/* 33 * Open the file read only. The call fails if the file doesn't exist. 34 * 35 * Returns NULL on failure. 36 */ 37ZipFile* openReadOnly(const char* fileName) 38{ 39 ZipFile* zip; 40 status_t result; 41 42 zip = new ZipFile; 43 result = zip->open(fileName, ZipFile::kOpenReadOnly); 44 if (result != NO_ERROR) { 45 if (result == NAME_NOT_FOUND) 46 fprintf(stderr, "ERROR: '%s' not found\n", fileName); 47 else if (result == PERMISSION_DENIED) 48 fprintf(stderr, "ERROR: '%s' access denied\n", fileName); 49 else 50 fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n", 51 fileName); 52 delete zip; 53 return NULL; 54 } 55 56 return zip; 57} 58 59/* 60 * Open the file read-write. The file will be created if it doesn't 61 * already exist and "okayToCreate" is set. 62 * 63 * Returns NULL on failure. 64 */ 65ZipFile* openReadWrite(const char* fileName, bool okayToCreate) 66{ 67 ZipFile* zip = NULL; 68 status_t result; 69 int flags; 70 71 flags = ZipFile::kOpenReadWrite; 72 if (okayToCreate) 73 flags |= ZipFile::kOpenCreate; 74 75 zip = new ZipFile; 76 result = zip->open(fileName, flags); 77 if (result != NO_ERROR) { 78 delete zip; 79 zip = NULL; 80 goto bail; 81 } 82 83bail: 84 return zip; 85} 86 87 88/* 89 * Return a short string describing the compression method. 90 */ 91const char* compressionName(int method) 92{ 93 if (method == ZipEntry::kCompressStored) 94 return "Stored"; 95 else if (method == ZipEntry::kCompressDeflated) 96 return "Deflated"; 97 else 98 return "Unknown"; 99} 100 101/* 102 * Return the percent reduction in size (0% == no compression). 103 */ 104int calcPercent(long uncompressedLen, long compressedLen) 105{ 106 if (!uncompressedLen) 107 return 0; 108 else 109 return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5); 110} 111 112/* 113 * Handle the "list" command, which can be a simple file dump or 114 * a verbose listing. 115 * 116 * The verbose listing closely matches the output of the Info-ZIP "unzip" 117 * command. 118 */ 119int doList(Bundle* bundle) 120{ 121 int result = 1; 122 ZipFile* zip = NULL; 123 const ZipEntry* entry; 124 long totalUncLen, totalCompLen; 125 const char* zipFileName; 126 127 if (bundle->getFileSpecCount() != 1) { 128 fprintf(stderr, "ERROR: specify zip file name (only)\n"); 129 goto bail; 130 } 131 zipFileName = bundle->getFileSpecEntry(0); 132 133 zip = openReadOnly(zipFileName); 134 if (zip == NULL) 135 goto bail; 136 137 int count, i; 138 139 if (bundle->getVerbose()) { 140 printf("Archive: %s\n", zipFileName); 141 printf( 142 " Length Method Size Ratio Date Time CRC-32 Name\n"); 143 printf( 144 "-------- ------ ------- ----- ---- ---- ------ ----\n"); 145 } 146 147 totalUncLen = totalCompLen = 0; 148 149 count = zip->getNumEntries(); 150 for (i = 0; i < count; i++) { 151 entry = zip->getEntryByIndex(i); 152 if (bundle->getVerbose()) { 153 char dateBuf[32]; 154 time_t when; 155 156 when = entry->getModWhen(); 157 strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M", 158 localtime(&when)); 159 160 printf("%8ld %-7.7s %7ld %3d%% %s %08lx %s\n", 161 (long) entry->getUncompressedLen(), 162 compressionName(entry->getCompressionMethod()), 163 (long) entry->getCompressedLen(), 164 calcPercent(entry->getUncompressedLen(), 165 entry->getCompressedLen()), 166 dateBuf, 167 entry->getCRC32(), 168 entry->getFileName()); 169 } else { 170 printf("%s\n", entry->getFileName()); 171 } 172 173 totalUncLen += entry->getUncompressedLen(); 174 totalCompLen += entry->getCompressedLen(); 175 } 176 177 if (bundle->getVerbose()) { 178 printf( 179 "-------- ------- --- -------\n"); 180 printf("%8ld %7ld %2d%% %d files\n", 181 totalUncLen, 182 totalCompLen, 183 calcPercent(totalUncLen, totalCompLen), 184 zip->getNumEntries()); 185 } 186 187 if (bundle->getAndroidList()) { 188 AssetManager assets; 189 if (!assets.addAssetPath(String8(zipFileName), NULL)) { 190 fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n"); 191 goto bail; 192 } 193 194 const ResTable& res = assets.getResources(false); 195 if (&res == NULL) { 196 printf("\nNo resource table found.\n"); 197 } else { 198 printf("\nResource table:\n"); 199 res.print(false); 200 } 201 202 Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml", 203 Asset::ACCESS_BUFFER); 204 if (manifestAsset == NULL) { 205 printf("\nNo AndroidManifest.xml found.\n"); 206 } else { 207 printf("\nAndroid manifest:\n"); 208 ResXMLTree tree; 209 tree.setTo(manifestAsset->getBuffer(true), 210 manifestAsset->getLength()); 211 printXMLBlock(&tree); 212 } 213 delete manifestAsset; 214 } 215 216 result = 0; 217 218bail: 219 delete zip; 220 return result; 221} 222 223static ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes) 224{ 225 size_t N = tree.getAttributeCount(); 226 for (size_t i=0; i<N; i++) { 227 if (tree.getAttributeNameResID(i) == attrRes) { 228 return (ssize_t)i; 229 } 230 } 231 return -1; 232} 233 234static String8 getAttribute(const ResXMLTree& tree, const char* ns, 235 const char* attr, String8* outError) 236{ 237 ssize_t idx = tree.indexOfAttribute(ns, attr); 238 if (idx < 0) { 239 return String8(); 240 } 241 Res_value value; 242 if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 243 if (value.dataType != Res_value::TYPE_STRING) { 244 if (outError != NULL) *outError = "attribute is not a string value"; 245 return String8(); 246 } 247 } 248 size_t len; 249 const uint16_t* str = tree.getAttributeStringValue(idx, &len); 250 return str ? String8(str, len) : String8(); 251} 252 253static String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError) 254{ 255 ssize_t idx = indexOfAttribute(tree, attrRes); 256 if (idx < 0) { 257 return String8(); 258 } 259 Res_value value; 260 if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 261 if (value.dataType != Res_value::TYPE_STRING) { 262 if (outError != NULL) *outError = "attribute is not a string value"; 263 return String8(); 264 } 265 } 266 size_t len; 267 const uint16_t* str = tree.getAttributeStringValue(idx, &len); 268 return str ? String8(str, len) : String8(); 269} 270 271static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, 272 String8* outError, int32_t defValue = -1) 273{ 274 ssize_t idx = indexOfAttribute(tree, attrRes); 275 if (idx < 0) { 276 return defValue; 277 } 278 Res_value value; 279 if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 280 if (value.dataType < Res_value::TYPE_FIRST_INT 281 || value.dataType > Res_value::TYPE_LAST_INT) { 282 if (outError != NULL) *outError = "attribute is not an integer value"; 283 return defValue; 284 } 285 } 286 return value.data; 287} 288 289static String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree, 290 uint32_t attrRes, String8* outError) 291{ 292 ssize_t idx = indexOfAttribute(tree, attrRes); 293 if (idx < 0) { 294 return String8(); 295 } 296 Res_value value; 297 if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 298 if (value.dataType == Res_value::TYPE_STRING) { 299 size_t len; 300 const uint16_t* str = tree.getAttributeStringValue(idx, &len); 301 return str ? String8(str, len) : String8(); 302 } 303 resTable->resolveReference(&value, 0); 304 if (value.dataType != Res_value::TYPE_STRING) { 305 if (outError != NULL) *outError = "attribute is not a string value"; 306 return String8(); 307 } 308 } 309 size_t len; 310 const Res_value* value2 = &value; 311 const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len); 312 return str ? String8(str, len) : String8(); 313} 314 315// These are attribute resource constants for the platform, as found 316// in android.R.attr 317enum { 318 NAME_ATTR = 0x01010003, 319 VERSION_CODE_ATTR = 0x0101021b, 320 VERSION_NAME_ATTR = 0x0101021c, 321 LABEL_ATTR = 0x01010001, 322 ICON_ATTR = 0x01010002, 323 MIN_SDK_VERSION_ATTR = 0x0101020c, 324 REQ_TOUCH_SCREEN_ATTR = 0x01010227, 325 REQ_KEYBOARD_TYPE_ATTR = 0x01010228, 326 REQ_HARD_KEYBOARD_ATTR = 0x01010229, 327 REQ_NAVIGATION_ATTR = 0x0101022a, 328 REQ_FIVE_WAY_NAV_ATTR = 0x01010232, 329 TARGET_SDK_VERSION_ATTR = 0x01010270, 330 TEST_ONLY_ATTR = 0x01010272, 331 DENSITY_ATTR = 0x0101026c, 332}; 333 334const char *getComponentName(String8 &pkgName, String8 &componentName) { 335 ssize_t idx = componentName.find("."); 336 String8 retStr(pkgName); 337 if (idx == 0) { 338 retStr += componentName; 339 } else if (idx < 0) { 340 retStr += "."; 341 retStr += componentName; 342 } else { 343 return componentName.string(); 344 } 345 return retStr.string(); 346} 347 348/* 349 * Handle the "dump" command, to extract select data from an archive. 350 */ 351int doDump(Bundle* bundle) 352{ 353 status_t result = UNKNOWN_ERROR; 354 Asset* asset = NULL; 355 356 if (bundle->getFileSpecCount() < 1) { 357 fprintf(stderr, "ERROR: no dump option specified\n"); 358 return 1; 359 } 360 361 if (bundle->getFileSpecCount() < 2) { 362 fprintf(stderr, "ERROR: no dump file specified\n"); 363 return 1; 364 } 365 366 const char* option = bundle->getFileSpecEntry(0); 367 const char* filename = bundle->getFileSpecEntry(1); 368 369 AssetManager assets; 370 void* assetsCookie; 371 if (!assets.addAssetPath(String8(filename), &assetsCookie)) { 372 fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n"); 373 return 1; 374 } 375 376 const ResTable& res = assets.getResources(false); 377 if (&res == NULL) { 378 fprintf(stderr, "ERROR: dump failed because no resource table was found\n"); 379 goto bail; 380 } 381 382 if (strcmp("resources", option) == 0) { 383 res.print(bundle->getValues()); 384 385 } else if (strcmp("xmltree", option) == 0) { 386 if (bundle->getFileSpecCount() < 3) { 387 fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); 388 goto bail; 389 } 390 391 for (int i=2; i<bundle->getFileSpecCount(); i++) { 392 const char* resname = bundle->getFileSpecEntry(i); 393 ResXMLTree tree; 394 asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); 395 if (asset == NULL) { 396 fprintf(stderr, "ERROR: dump failed because resource %p found\n", resname); 397 goto bail; 398 } 399 400 if (tree.setTo(asset->getBuffer(true), 401 asset->getLength()) != NO_ERROR) { 402 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); 403 goto bail; 404 } 405 tree.restart(); 406 printXMLBlock(&tree); 407 delete asset; 408 asset = NULL; 409 } 410 411 } else if (strcmp("xmlstrings", option) == 0) { 412 if (bundle->getFileSpecCount() < 3) { 413 fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); 414 goto bail; 415 } 416 417 for (int i=2; i<bundle->getFileSpecCount(); i++) { 418 const char* resname = bundle->getFileSpecEntry(i); 419 ResXMLTree tree; 420 asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); 421 if (asset == NULL) { 422 fprintf(stderr, "ERROR: dump failed because resource %p found\n", resname); 423 goto bail; 424 } 425 426 if (tree.setTo(asset->getBuffer(true), 427 asset->getLength()) != NO_ERROR) { 428 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); 429 goto bail; 430 } 431 printStringPool(&tree.getStrings()); 432 delete asset; 433 asset = NULL; 434 } 435 436 } else { 437 ResXMLTree tree; 438 asset = assets.openNonAsset("AndroidManifest.xml", 439 Asset::ACCESS_BUFFER); 440 if (asset == NULL) { 441 fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n"); 442 goto bail; 443 } 444 445 if (tree.setTo(asset->getBuffer(true), 446 asset->getLength()) != NO_ERROR) { 447 fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n"); 448 goto bail; 449 } 450 tree.restart(); 451 452 if (strcmp("permissions", option) == 0) { 453 size_t len; 454 ResXMLTree::event_code_t code; 455 int depth = 0; 456 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { 457 if (code == ResXMLTree::END_TAG) { 458 depth--; 459 continue; 460 } 461 if (code != ResXMLTree::START_TAG) { 462 continue; 463 } 464 depth++; 465 String8 tag(tree.getElementName(&len)); 466 //printf("Depth %d tag %s\n", depth, tag.string()); 467 if (depth == 1) { 468 if (tag != "manifest") { 469 fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); 470 goto bail; 471 } 472 String8 pkg = getAttribute(tree, NULL, "package", NULL); 473 printf("package: %s\n", pkg.string()); 474 } else if (depth == 2 && tag == "permission") { 475 String8 error; 476 String8 name = getAttribute(tree, NAME_ATTR, &error); 477 if (error != "") { 478 fprintf(stderr, "ERROR: %s\n", error.string()); 479 goto bail; 480 } 481 printf("permission: %s\n", name.string()); 482 } else if (depth == 2 && tag == "uses-permission") { 483 String8 error; 484 String8 name = getAttribute(tree, NAME_ATTR, &error); 485 if (error != "") { 486 fprintf(stderr, "ERROR: %s\n", error.string()); 487 goto bail; 488 } 489 printf("uses-permission: %s\n", name.string()); 490 } 491 } 492 } else if (strcmp("badging", option) == 0) { 493 size_t len; 494 ResXMLTree::event_code_t code; 495 int depth = 0; 496 String8 error; 497 bool withinActivity = false; 498 bool isMainActivity = false; 499 bool isLauncherActivity = false; 500 bool withinApplication = false; 501 bool withinReceiver = false; 502 String8 pkg; 503 String8 activityName; 504 String8 activityLabel; 505 String8 activityIcon; 506 String8 receiverName; 507 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { 508 if (code == ResXMLTree::END_TAG) { 509 depth--; 510 continue; 511 } 512 if (code != ResXMLTree::START_TAG) { 513 continue; 514 } 515 depth++; 516 String8 tag(tree.getElementName(&len)); 517 //printf("Depth %d tag %s\n", depth, tag.string()); 518 if (depth == 1) { 519 if (tag != "manifest") { 520 fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); 521 goto bail; 522 } 523 pkg = getAttribute(tree, NULL, "package", NULL); 524 printf("package: name='%s' ", pkg.string()); 525 int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error); 526 if (error != "") { 527 fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string()); 528 goto bail; 529 } 530 if (versionCode > 0) { 531 printf("versionCode='%d' ", versionCode); 532 } else { 533 printf("versionCode='' "); 534 } 535 String8 versionName = getAttribute(tree, VERSION_NAME_ATTR, &error); 536 if (error != "") { 537 fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string()); 538 goto bail; 539 } 540 printf("versionName='%s'\n", versionName.string()); 541 } else if (depth == 2) { 542 withinApplication = false; 543 if (tag == "application") { 544 withinApplication = true; 545 String8 label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); 546 if (error != "") { 547 fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string()); 548 goto bail; 549 } 550 printf("application: label='%s' ", label.string()); 551 String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 552 if (error != "") { 553 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); 554 goto bail; 555 } 556 printf("icon='%s'\n", icon.string()); 557 int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0); 558 if (error != "") { 559 fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string()); 560 goto bail; 561 } 562 if (testOnly != 0) { 563 printf("testOnly='%d'\n", testOnly); 564 } 565 } else if (tag == "uses-sdk") { 566 int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error); 567 if (error != "") { 568 error = ""; 569 String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error); 570 if (error != "") { 571 fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n", 572 error.string()); 573 goto bail; 574 } 575 printf("sdkVersion:'%s'\n", name.string()); 576 } else if (code != -1) { 577 printf("sdkVersion:'%d'\n", code); 578 } 579 code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error); 580 if (error != "") { 581 error = ""; 582 String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error); 583 if (error != "") { 584 fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n", 585 error.string()); 586 goto bail; 587 } 588 printf("targetSdkVersion:'%s'\n", name.string()); 589 } else if (code != -1) { 590 printf("targetSdkVersion:'%d'\n", code); 591 } 592 } else if (tag == "uses-configuration") { 593 int32_t reqTouchScreen = getIntegerAttribute(tree, 594 REQ_TOUCH_SCREEN_ATTR, NULL, 0); 595 int32_t reqKeyboardType = getIntegerAttribute(tree, 596 REQ_KEYBOARD_TYPE_ATTR, NULL, 0); 597 int32_t reqHardKeyboard = getIntegerAttribute(tree, 598 REQ_HARD_KEYBOARD_ATTR, NULL, 0); 599 int32_t reqNavigation = getIntegerAttribute(tree, 600 REQ_NAVIGATION_ATTR, NULL, 0); 601 int32_t reqFiveWayNav = getIntegerAttribute(tree, 602 REQ_FIVE_WAY_NAV_ATTR, NULL, 0); 603 printf("uses-configuation:"); 604 if (reqTouchScreen != 0) { 605 printf(" reqTouchScreen='%d'", reqTouchScreen); 606 } 607 if (reqKeyboardType != 0) { 608 printf(" reqKeyboardType='%d'", reqKeyboardType); 609 } 610 if (reqHardKeyboard != 0) { 611 printf(" reqHardKeyboard='%d'", reqHardKeyboard); 612 } 613 if (reqNavigation != 0) { 614 printf(" reqNavigation='%d'", reqNavigation); 615 } 616 if (reqFiveWayNav != 0) { 617 printf(" reqFiveWayNav='%d'", reqFiveWayNav); 618 } 619 printf("\n"); 620 } else if (tag == "supports-density") { 621 int32_t dens = getIntegerAttribute(tree, DENSITY_ATTR, &error); 622 if (error != "") { 623 fprintf(stderr, "ERROR getting 'android:density' attribute: %s\n", 624 error.string()); 625 goto bail; 626 } 627 printf("supports-density:'%d'\n", dens); 628 } 629 } else if (depth == 3 && withinApplication) { 630 withinActivity = false; 631 withinReceiver = false; 632 if(tag == "activity") { 633 withinActivity = true; 634 activityName = getAttribute(tree, NAME_ATTR, &error); 635 if (error != "") { 636 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); 637 goto bail; 638 } 639 640 activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); 641 if (error != "") { 642 fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string()); 643 goto bail; 644 } 645 646 activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 647 if (error != "") { 648 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); 649 goto bail; 650 } 651 } else if (tag == "uses-library") { 652 String8 libraryName = getAttribute(tree, NAME_ATTR, &error); 653 if (error != "") { 654 fprintf(stderr, "ERROR getting 'android:name' attribute for uses-library: %s\n", error.string()); 655 goto bail; 656 } 657 printf("uses-library:'%s'\n", libraryName.string()); 658 } else if (tag == "receiver") { 659 withinReceiver = true; 660 receiverName = getAttribute(tree, NAME_ATTR, &error); 661 662 if (error != "") { 663 fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string()); 664 goto bail; 665 } 666 } 667 } else if (depth == 5) { 668 if (withinActivity) { 669 if (tag == "action") { 670 //printf("LOG: action tag\n"); 671 String8 action = getAttribute(tree, NAME_ATTR, &error); 672 if (error != "") { 673 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); 674 goto bail; 675 } 676 if (action == "android.intent.action.MAIN") { 677 isMainActivity = true; 678 //printf("LOG: isMainActivity==true\n"); 679 } 680 } else if (tag == "category") { 681 String8 category = getAttribute(tree, NAME_ATTR, &error); 682 if (error != "") { 683 fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string()); 684 goto bail; 685 } 686 if (category == "android.intent.category.LAUNCHER") { 687 isLauncherActivity = true; 688 //printf("LOG: isLauncherActivity==true\n"); 689 } 690 } 691 } else if (withinReceiver) { 692 if (tag == "action") { 693 String8 action = getAttribute(tree, NAME_ATTR, &error); 694 if (error != "") { 695 fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string()); 696 goto bail; 697 } 698 if (action == "android.appwidget.action.APPWIDGET_UPDATE") { 699 const char *rName = getComponentName(pkg, receiverName); 700 if (rName != NULL) { 701 printf("gadget-receiver:'%s/%s'\n", pkg.string(), rName); 702 } 703 } 704 } 705 } 706 } 707 708 if (depth < 2) { 709 withinApplication = false; 710 } 711 if (depth < 3) { 712 //if (withinActivity) printf("LOG: withinActivity==false\n"); 713 withinActivity = false; 714 withinReceiver = false; 715 } 716 717 if (depth < 5) { 718 //if (isMainActivity) printf("LOG: isMainActivity==false\n"); 719 //if (isLauncherActivity) printf("LOG: isLauncherActivity==false\n"); 720 isMainActivity = false; 721 isLauncherActivity = false; 722 } 723 724 if (withinActivity && isMainActivity && isLauncherActivity) { 725 printf("launchable activity:"); 726 const char *aName = getComponentName(pkg, activityName); 727 if (aName != NULL) { 728 printf(" name='%s'", aName); 729 } 730 printf("label='%s' icon='%s'\n", 731 activityLabel.string(), 732 activityIcon.string()); 733 } 734 } 735 736 printf("locales:"); 737 Vector<String8> locales; 738 res.getLocales(&locales); 739 const size_t NL = locales.size(); 740 for (size_t i=0; i<NL; i++) { 741 const char* localeStr = locales[i].string(); 742 if (localeStr == NULL || strlen(localeStr) == 0) { 743 localeStr = "--_--"; 744 } 745 printf(" '%s'", localeStr); 746 } 747 printf("\n"); 748 749 Vector<ResTable_config> configs; 750 res.getConfigurations(&configs); 751 SortedVector<int> densities; 752 const size_t NC = configs.size(); 753 for (size_t i=0; i<NC; i++) { 754 int dens = configs[i].density; 755 if (dens == 0) dens = 160; 756 densities.add(dens); 757 } 758 759 printf("densities:"); 760 const size_t ND = densities.size(); 761 for (size_t i=0; i<ND; i++) { 762 printf(" '%d'", densities[i]); 763 } 764 printf("\n"); 765 766 AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib"); 767 if (dir != NULL) { 768 if (dir->getFileCount() > 0) { 769 printf("native-code:"); 770 for (size_t i=0; i<dir->getFileCount(); i++) { 771 printf(" '%s'", dir->getFileName(i).string()); 772 } 773 printf("\n"); 774 } 775 delete dir; 776 } 777 } else if (strcmp("configurations", option) == 0) { 778 Vector<ResTable_config> configs; 779 res.getConfigurations(&configs); 780 const size_t N = configs.size(); 781 for (size_t i=0; i<N; i++) { 782 printf("%s\n", configs[i].toString().string()); 783 } 784 } else { 785 fprintf(stderr, "ERROR: unknown dump option '%s'\n", option); 786 goto bail; 787 } 788 } 789 790 result = NO_ERROR; 791 792bail: 793 if (asset) { 794 delete asset; 795 } 796 return (result != NO_ERROR); 797} 798 799 800/* 801 * Handle the "add" command, which wants to add files to a new or 802 * pre-existing archive. 803 */ 804int doAdd(Bundle* bundle) 805{ 806 ZipFile* zip = NULL; 807 status_t result = UNKNOWN_ERROR; 808 const char* zipFileName; 809 810 if (bundle->getUpdate()) { 811 /* avoid confusion */ 812 fprintf(stderr, "ERROR: can't use '-u' with add\n"); 813 goto bail; 814 } 815 816 if (bundle->getFileSpecCount() < 1) { 817 fprintf(stderr, "ERROR: must specify zip file name\n"); 818 goto bail; 819 } 820 zipFileName = bundle->getFileSpecEntry(0); 821 822 if (bundle->getFileSpecCount() < 2) { 823 fprintf(stderr, "NOTE: nothing to do\n"); 824 goto bail; 825 } 826 827 zip = openReadWrite(zipFileName, true); 828 if (zip == NULL) { 829 fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName); 830 goto bail; 831 } 832 833 for (int i = 1; i < bundle->getFileSpecCount(); i++) { 834 const char* fileName = bundle->getFileSpecEntry(i); 835 836 if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) { 837 printf(" '%s'... (from gzip)\n", fileName); 838 result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL); 839 } else { 840 printf(" '%s'...\n", fileName); 841 result = zip->add(fileName, bundle->getCompressionMethod(), NULL); 842 } 843 if (result != NO_ERROR) { 844 fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName); 845 if (result == NAME_NOT_FOUND) 846 fprintf(stderr, ": file not found\n"); 847 else if (result == ALREADY_EXISTS) 848 fprintf(stderr, ": already exists in archive\n"); 849 else 850 fprintf(stderr, "\n"); 851 goto bail; 852 } 853 } 854 855 result = NO_ERROR; 856 857bail: 858 delete zip; 859 return (result != NO_ERROR); 860} 861 862 863/* 864 * Delete files from an existing archive. 865 */ 866int doRemove(Bundle* bundle) 867{ 868 ZipFile* zip = NULL; 869 status_t result = UNKNOWN_ERROR; 870 const char* zipFileName; 871 872 if (bundle->getFileSpecCount() < 1) { 873 fprintf(stderr, "ERROR: must specify zip file name\n"); 874 goto bail; 875 } 876 zipFileName = bundle->getFileSpecEntry(0); 877 878 if (bundle->getFileSpecCount() < 2) { 879 fprintf(stderr, "NOTE: nothing to do\n"); 880 goto bail; 881 } 882 883 zip = openReadWrite(zipFileName, false); 884 if (zip == NULL) { 885 fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n", 886 zipFileName); 887 goto bail; 888 } 889 890 for (int i = 1; i < bundle->getFileSpecCount(); i++) { 891 const char* fileName = bundle->getFileSpecEntry(i); 892 ZipEntry* entry; 893 894 entry = zip->getEntryByName(fileName); 895 if (entry == NULL) { 896 printf(" '%s' NOT FOUND\n", fileName); 897 continue; 898 } 899 900 result = zip->remove(entry); 901 902 if (result != NO_ERROR) { 903 fprintf(stderr, "Unable to delete '%s' from '%s'\n", 904 bundle->getFileSpecEntry(i), zipFileName); 905 goto bail; 906 } 907 } 908 909 /* update the archive */ 910 zip->flush(); 911 912bail: 913 delete zip; 914 return (result != NO_ERROR); 915} 916 917 918/* 919 * Package up an asset directory and associated application files. 920 */ 921int doPackage(Bundle* bundle) 922{ 923 const char* outputAPKFile; 924 int retVal = 1; 925 status_t err; 926 sp<AaptAssets> assets; 927 int N; 928 929 // -c zz_ZZ means do pseudolocalization 930 ResourceFilter filter; 931 err = filter.parse(bundle->getConfigurations()); 932 if (err != NO_ERROR) { 933 goto bail; 934 } 935 if (filter.containsPseudo()) { 936 bundle->setPseudolocalize(true); 937 } 938 939 N = bundle->getFileSpecCount(); 940 if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0 941 && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) { 942 fprintf(stderr, "ERROR: no input files\n"); 943 goto bail; 944 } 945 946 outputAPKFile = bundle->getOutputAPKFile(); 947 948 // Make sure the filenames provided exist and are of the appropriate type. 949 if (outputAPKFile) { 950 FileType type; 951 type = getFileType(outputAPKFile); 952 if (type != kFileTypeNonexistent && type != kFileTypeRegular) { 953 fprintf(stderr, 954 "ERROR: output file '%s' exists but is not regular file\n", 955 outputAPKFile); 956 goto bail; 957 } 958 } 959 960 // Load the assets. 961 assets = new AaptAssets(); 962 err = assets->slurpFromArgs(bundle); 963 if (err < 0) { 964 goto bail; 965 } 966 967 if (bundle->getVerbose()) { 968 assets->print(); 969 } 970 971 // If they asked for any files that need to be compiled, do so. 972 if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) { 973 err = buildResources(bundle, assets); 974 if (err != 0) { 975 goto bail; 976 } 977 } 978 979 // At this point we've read everything and processed everything. From here 980 // on out it's just writing output files. 981 if (SourcePos::hasErrors()) { 982 goto bail; 983 } 984 985 // Write out R.java constants 986 if (assets->getPackage() == assets->getSymbolsPrivatePackage()) { 987 err = writeResourceSymbols(bundle, assets, assets->getPackage(), true); 988 if (err < 0) { 989 goto bail; 990 } 991 } else { 992 err = writeResourceSymbols(bundle, assets, assets->getPackage(), false); 993 if (err < 0) { 994 goto bail; 995 } 996 err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true); 997 if (err < 0) { 998 goto bail; 999 } 1000 } 1001 1002 // Write the apk 1003 if (outputAPKFile) { 1004 err = writeAPK(bundle, assets, String8(outputAPKFile)); 1005 if (err != NO_ERROR) { 1006 fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputAPKFile); 1007 goto bail; 1008 } 1009 } 1010 1011 retVal = 0; 1012bail: 1013 if (SourcePos::hasErrors()) { 1014 SourcePos::printErrors(stderr); 1015 } 1016 return retVal; 1017} 1018