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