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