2 // Copyright 2006 The Android Open Source Project 
   4 // Android Asset Packaging Tool main entry point. 
   8 #include "ResourceTable.h" 
  11 #include <utils/Log.h> 
  12 #include <utils/threads.h> 
  13 #include <utils/List.h> 
  14 #include <utils/Errors.h> 
  19 using namespace android
; 
  22  * Show version info.  All the cool kids do it. 
  24 int doVersion(Bundle
* bundle
) 
  26     if (bundle
->getFileSpecCount() != 0) 
  27         printf("(ignoring extra arguments)\n"); 
  28     printf("Android Asset Packaging Tool, v0.2\n"); 
  35  * Open the file read only.  The call fails if the file doesn't exist. 
  37  * Returns NULL on failure. 
  39 ZipFile
* openReadOnly(const char* fileName
) 
  45     result 
= zip
->open(fileName
, ZipFile::kOpenReadOnly
); 
  46     if (result 
!= NO_ERROR
) { 
  47         if (result 
== NAME_NOT_FOUND
) 
  48             fprintf(stderr
, "ERROR: '%s' not found\n", fileName
); 
  49         else if (result 
== PERMISSION_DENIED
) 
  50             fprintf(stderr
, "ERROR: '%s' access denied\n", fileName
); 
  52             fprintf(stderr
, "ERROR: failed opening '%s' as Zip file\n", 
  62  * Open the file read-write.  The file will be created if it doesn't 
  63  * already exist and "okayToCreate" is set. 
  65  * Returns NULL on failure. 
  67 ZipFile
* openReadWrite(const char* fileName
, bool okayToCreate
) 
  73     flags 
= ZipFile::kOpenReadWrite
; 
  75         flags 
|= ZipFile::kOpenCreate
; 
  78     result 
= zip
->open(fileName
, flags
); 
  79     if (result 
!= NO_ERROR
) { 
  91  * Return a short string describing the compression method. 
  93 const char* compressionName(int method
) 
  95     if (method 
== ZipEntry::kCompressStored
) 
  97     else if (method 
== ZipEntry::kCompressDeflated
) 
 104  * Return the percent reduction in size (0% == no compression). 
 106 int calcPercent(long uncompressedLen
, long compressedLen
) 
 108     if (!uncompressedLen
) 
 111         return (int) (100.0 - (compressedLen 
* 100.0) / uncompressedLen 
+ 0.5); 
 115  * Handle the "list" command, which can be a simple file dump or 
 118  * The verbose listing closely matches the output of the Info-ZIP "unzip" 
 121 int doList(Bundle
* bundle
) 
 125     const ZipEntry
* entry
; 
 126     long totalUncLen
, totalCompLen
; 
 127     const char* zipFileName
; 
 129     if (bundle
->getFileSpecCount() != 1) { 
 130         fprintf(stderr
, "ERROR: specify zip file name (only)\n"); 
 133     zipFileName 
= bundle
->getFileSpecEntry(0); 
 135     zip 
= openReadOnly(zipFileName
); 
 141     if (bundle
->getVerbose()) { 
 142         printf("Archive:  %s\n", zipFileName
); 
 144             " Length   Method    Size  Ratio   Date   Time   CRC-32    Name\n"); 
 146             "--------  ------  ------- -----   ----   ----   ------    ----\n"); 
 149     totalUncLen 
= totalCompLen 
= 0; 
 151     count 
= zip
->getNumEntries(); 
 152     for (i 
= 0; i 
< count
; i
++) { 
 153         entry 
= zip
->getEntryByIndex(i
); 
 154         if (bundle
->getVerbose()) { 
 158             when 
= entry
->getModWhen(); 
 159             strftime(dateBuf
, sizeof(dateBuf
), "%m-%d-%y %H:%M", 
 162             printf("%8ld  %-7.7s %7ld %3d%%  %s  %08lx  %s\n", 
 163                 (long) entry
->getUncompressedLen(), 
 164                 compressionName(entry
->getCompressionMethod()), 
 165                 (long) entry
->getCompressedLen(), 
 166                 calcPercent(entry
->getUncompressedLen(), 
 167                             entry
->getCompressedLen()), 
 170                 entry
->getFileName()); 
 172             printf("%s\n", entry
->getFileName()); 
 175         totalUncLen 
+= entry
->getUncompressedLen(); 
 176         totalCompLen 
+= entry
->getCompressedLen(); 
 179     if (bundle
->getVerbose()) { 
 181         "--------          -------  ---                            -------\n"); 
 182         printf("%8ld          %7ld  %2d%%                            %d files\n", 
 185             calcPercent(totalUncLen
, totalCompLen
), 
 186             zip
->getNumEntries()); 
 189     if (bundle
->getAndroidList()) { 
 191         if (!assets
.addAssetPath(String8(zipFileName
), NULL
)) { 
 192             fprintf(stderr
, "ERROR: list -a failed because assets could not be loaded\n"); 
 196         const ResTable
& res 
= assets
.getResources(false); 
 198             printf("\nNo resource table found.\n"); 
 200             printf("\nResource table:\n"); 
 204         Asset
* manifestAsset 
= assets
.openNonAsset("AndroidManifest.xml", 
 205                                                    Asset::ACCESS_BUFFER
); 
 206         if (manifestAsset 
== NULL
) { 
 207             printf("\nNo AndroidManifest.xml found.\n"); 
 209             printf("\nAndroid manifest:\n"); 
 211             tree
.setTo(manifestAsset
->getBuffer(true), 
 212                        manifestAsset
->getLength()); 
 213             printXMLBlock(&tree
); 
 215         delete manifestAsset
; 
 225 static ssize_t 
indexOfAttribute(const ResXMLTree
& tree
, uint32_t attrRes
) 
 227     size_t N 
= tree
.getAttributeCount(); 
 228     for (size_t i
=0; i
<N
; i
++) { 
 229         if (tree
.getAttributeNameResID(i
) == attrRes
) { 
 236 String8 
getAttribute(const ResXMLTree
& tree
, const char* ns
, 
 237                             const char* attr
, String8
* outError
) 
 239     ssize_t idx 
= tree
.indexOfAttribute(ns
, attr
); 
 244     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 245         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 246             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 251     const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 252     return str 
? String8(str
, len
) : String8(); 
 255 static String8 
getAttribute(const ResXMLTree
& tree
, uint32_t attrRes
, String8
* outError
) 
 257     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 262     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 263         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 264             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 269     const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 270     return str 
? String8(str
, len
) : String8(); 
 273 static int32_t getIntegerAttribute(const ResXMLTree
& tree
, uint32_t attrRes
, 
 274         String8
* outError
, int32_t defValue 
= -1) 
 276     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 281     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 282         if (value
.dataType 
< Res_value::TYPE_FIRST_INT
 
 283                 || value
.dataType 
> Res_value::TYPE_LAST_INT
) { 
 284             if (outError 
!= NULL
) *outError 
= "attribute is not an integer value"; 
 291 static String8 
getResolvedAttribute(const ResTable
* resTable
, const ResXMLTree
& tree
, 
 292         uint32_t attrRes
, String8
* outError
) 
 294     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 299     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 300         if (value
.dataType 
== Res_value::TYPE_STRING
) { 
 302             const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 303             return str 
? String8(str
, len
) : String8(); 
 305         resTable
->resolveReference(&value
, 0); 
 306         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 307             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 312     const Res_value
* value2 
= &value
; 
 313     const char16_t* str 
= const_cast<ResTable
*>(resTable
)->valueToString(value2
, 0, NULL
, &len
); 
 314     return str 
? String8(str
, len
) : String8(); 
 317 // These are attribute resource constants for the platform, as found 
 320     NAME_ATTR 
= 0x01010003, 
 321     VERSION_CODE_ATTR 
= 0x0101021b, 
 322     VERSION_NAME_ATTR 
= 0x0101021c, 
 323     LABEL_ATTR 
= 0x01010001, 
 324     ICON_ATTR 
= 0x01010002, 
 325     MIN_SDK_VERSION_ATTR 
= 0x0101020c, 
 326     MAX_SDK_VERSION_ATTR 
= 0x01010271, 
 327     REQ_TOUCH_SCREEN_ATTR 
= 0x01010227, 
 328     REQ_KEYBOARD_TYPE_ATTR 
= 0x01010228, 
 329     REQ_HARD_KEYBOARD_ATTR 
= 0x01010229, 
 330     REQ_NAVIGATION_ATTR 
= 0x0101022a, 
 331     REQ_FIVE_WAY_NAV_ATTR 
= 0x01010232, 
 332     TARGET_SDK_VERSION_ATTR 
= 0x01010270, 
 333     TEST_ONLY_ATTR 
= 0x01010272, 
 334     DENSITY_ATTR 
= 0x0101026c, 
 335     GL_ES_VERSION_ATTR 
= 0x01010281, 
 336     SMALL_SCREEN_ATTR 
= 0x01010284, 
 337     NORMAL_SCREEN_ATTR 
= 0x01010285, 
 338     LARGE_SCREEN_ATTR 
= 0x01010286, 
 339     REQUIRED_ATTR 
= 0x0101028e, 
 342 const char *getComponentName(String8 
&pkgName
, String8 
&componentName
) { 
 343     ssize_t idx 
= componentName
.find("."); 
 344     String8 
retStr(pkgName
); 
 346         retStr 
+= componentName
; 
 347     } else if (idx 
< 0) { 
 349         retStr 
+= componentName
; 
 351         return componentName
.string(); 
 353     return retStr
.string(); 
 357  * Handle the "dump" command, to extract select data from an archive. 
 359 int doDump(Bundle
* bundle
) 
 361     status_t result 
= UNKNOWN_ERROR
; 
 364     if (bundle
->getFileSpecCount() < 1) { 
 365         fprintf(stderr
, "ERROR: no dump option specified\n"); 
 369     if (bundle
->getFileSpecCount() < 2) { 
 370         fprintf(stderr
, "ERROR: no dump file specified\n"); 
 374     const char* option 
= bundle
->getFileSpecEntry(0); 
 375     const char* filename 
= bundle
->getFileSpecEntry(1); 
 379     if (!assets
.addAssetPath(String8(filename
), &assetsCookie
)) { 
 380         fprintf(stderr
, "ERROR: dump failed because assets could not be loaded\n"); 
 384     const ResTable
& res 
= assets
.getResources(false); 
 386         fprintf(stderr
, "ERROR: dump failed because no resource table was found\n"); 
 390     if (strcmp("resources", option
) == 0) { 
 391         res
.print(bundle
->getValues()); 
 393     } else if (strcmp("xmltree", option
) == 0) { 
 394         if (bundle
->getFileSpecCount() < 3) { 
 395             fprintf(stderr
, "ERROR: no dump xmltree resource file specified\n"); 
 399         for (int i
=2; i
<bundle
->getFileSpecCount(); i
++) { 
 400             const char* resname 
= bundle
->getFileSpecEntry(i
); 
 402             asset 
= assets
.openNonAsset(resname
, Asset::ACCESS_BUFFER
); 
 404                 fprintf(stderr
, "ERROR: dump failed because resource %s found\n", resname
); 
 408             if (tree
.setTo(asset
->getBuffer(true), 
 409                            asset
->getLength()) != NO_ERROR
) { 
 410                 fprintf(stderr
, "ERROR: Resource %s is corrupt\n", resname
); 
 414             printXMLBlock(&tree
); 
 420     } else if (strcmp("xmlstrings", option
) == 0) { 
 421         if (bundle
->getFileSpecCount() < 3) { 
 422             fprintf(stderr
, "ERROR: no dump xmltree resource file specified\n"); 
 426         for (int i
=2; i
<bundle
->getFileSpecCount(); i
++) { 
 427             const char* resname 
= bundle
->getFileSpecEntry(i
); 
 429             asset 
= assets
.openNonAsset(resname
, Asset::ACCESS_BUFFER
); 
 431                 fprintf(stderr
, "ERROR: dump failed because resource %s found\n", resname
); 
 435             if (tree
.setTo(asset
->getBuffer(true), 
 436                            asset
->getLength()) != NO_ERROR
) { 
 437                 fprintf(stderr
, "ERROR: Resource %s is corrupt\n", resname
); 
 440             printStringPool(&tree
.getStrings()); 
 447         asset 
= assets
.openNonAsset("AndroidManifest.xml", 
 448                                             Asset::ACCESS_BUFFER
); 
 450             fprintf(stderr
, "ERROR: dump failed because no AndroidManifest.xml found\n"); 
 454         if (tree
.setTo(asset
->getBuffer(true), 
 455                        asset
->getLength()) != NO_ERROR
) { 
 456             fprintf(stderr
, "ERROR: AndroidManifest.xml is corrupt\n"); 
 461         if (strcmp("permissions", option
) == 0) { 
 463             ResXMLTree::event_code_t code
; 
 465             while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 466                 if (code 
== ResXMLTree::END_TAG
) { 
 470                 if (code 
!= ResXMLTree::START_TAG
) { 
 474                 String8 
tag(tree
.getElementName(&len
)); 
 475                 //printf("Depth %d tag %s\n", depth, tag.string()); 
 477                     if (tag 
!= "manifest") { 
 478                         fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n"); 
 481                     String8 pkg 
= getAttribute(tree
, NULL
, "package", NULL
); 
 482                     printf("package: %s\n", pkg
.string()); 
 483                 } else if (depth 
== 2 && tag 
== "permission") { 
 485                     String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 487                         fprintf(stderr
, "ERROR: %s\n", error
.string()); 
 490                     printf("permission: %s\n", name
.string()); 
 491                 } else if (depth 
== 2 && tag 
== "uses-permission") { 
 493                     String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 495                         fprintf(stderr
, "ERROR: %s\n", error
.string()); 
 498                     printf("uses-permission: %s\n", name
.string()); 
 501         } else if (strcmp("badging", option
) == 0) { 
 503             ResXMLTree::event_code_t code
; 
 506             bool withinActivity 
= false; 
 507             bool isMainActivity 
= false; 
 508             bool isLauncherActivity 
= false; 
 509             bool isSearchable 
= false; 
 510             bool withinApplication 
= false; 
 511             bool withinReceiver 
= false; 
 512             bool withinService 
= false; 
 513             bool withinIntentFilter 
= false; 
 514             bool hasMainActivity 
= false; 
 515             bool hasOtherActivities 
= false; 
 516             bool hasOtherReceivers 
= false; 
 517             bool hasOtherServices 
= false; 
 518             bool hasWallpaperService 
= false; 
 519             bool hasImeService 
= false; 
 520             bool hasWidgetReceivers 
= false; 
 521             bool hasIntentFilter 
= false; 
 522             bool actMainActivity 
= false; 
 523             bool actWidgetReceivers 
= false; 
 524             bool actImeService 
= false; 
 525             bool actWallpaperService 
= false; 
 527             // This next group of variables is used to implement a group of 
 528             // backward-compatibility heuristics necessitated by the addition of 
 529             // some new uses-feature constants in 2.1 and 2.2. In most cases, the 
 530             // heuristic is "if an app requests a permission but doesn't explicitly 
 531             // request the corresponding <uses-feature>, presume it's there anyway". 
 532             bool specCameraFeature 
= false; // camera-related 
 533             bool specCameraAutofocusFeature 
= false; 
 534             bool reqCameraAutofocusFeature 
= false; 
 535             bool reqCameraFlashFeature 
= false; 
 536             bool hasCameraPermission 
= false; 
 537             bool specLocationFeature 
= false; // location-related 
 538             bool specNetworkLocFeature 
= false; 
 539             bool reqNetworkLocFeature 
= false; 
 540             bool specGpsFeature 
= false; 
 541             bool reqGpsFeature 
= false; 
 542             bool hasMockLocPermission 
= false; 
 543             bool hasCoarseLocPermission 
= false; 
 544             bool hasGpsPermission 
= false; 
 545             bool hasGeneralLocPermission 
= false; 
 546             bool specBluetoothFeature 
= false; // Bluetooth API-related 
 547             bool hasBluetoothPermission 
= false; 
 548             bool specMicrophoneFeature 
= false; // microphone-related 
 549             bool hasRecordAudioPermission 
= false; 
 550             bool specWiFiFeature 
= false; 
 551             bool hasWiFiPermission 
= false; 
 552             bool specTelephonyFeature 
= false; // telephony-related 
 553             bool reqTelephonySubFeature 
= false; 
 554             bool hasTelephonyPermission 
= false; 
 555             bool specTouchscreenFeature 
= false; // touchscreen-related 
 556             bool specMultitouchFeature 
= false; 
 557             bool reqDistinctMultitouchFeature 
= false; 
 558             // 2.2 also added some other features that apps can request, but that 
 559             // have no corresponding permission, so we cannot implement any 
 560             // back-compatibility heuristic for them. The below are thus unnecessary 
 561             // (but are retained here for documentary purposes.) 
 562             //bool specCompassFeature = false; 
 563             //bool specAccelerometerFeature = false; 
 564             //bool specProximityFeature = false; 
 565             //bool specAmbientLightFeature = false; 
 566             //bool specLiveWallpaperFeature = false; 
 570             int normalScreen 
= 1; 
 573             String8 activityName
; 
 574             String8 activityLabel
; 
 575             String8 activityIcon
; 
 576             String8 receiverName
; 
 578             while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 579                 if (code 
== ResXMLTree::END_TAG
) { 
 582                         withinApplication 
= false; 
 583                     } else if (depth 
< 3) { 
 584                         if (withinActivity 
&& isMainActivity 
&& isLauncherActivity
) { 
 585                             const char *aName 
= getComponentName(pkg
, activityName
); 
 587                                 printf("launchable activity name='%s'", aName
); 
 589                             printf("label='%s' icon='%s'\n", 
 590                                     activityLabel
.string(), 
 591                                     activityIcon
.string()); 
 593                         if (!hasIntentFilter
) { 
 594                             hasOtherActivities 
|= withinActivity
; 
 595                             hasOtherReceivers 
|= withinReceiver
; 
 596                             hasOtherServices 
|= withinService
; 
 598                         withinActivity 
= false; 
 599                         withinService 
= false; 
 600                         withinReceiver 
= false; 
 601                         hasIntentFilter 
= false; 
 602                         isMainActivity 
= isLauncherActivity 
= false; 
 603                     } else if (depth 
< 4) { 
 604                         if (withinIntentFilter
) { 
 605                             if (withinActivity
) { 
 606                                 hasMainActivity 
|= actMainActivity
; 
 607                                 hasOtherActivities 
|= !actMainActivity
; 
 608                             } else if (withinReceiver
) { 
 609                                 hasWidgetReceivers 
|= actWidgetReceivers
; 
 610                                 hasOtherReceivers 
|= !actWidgetReceivers
; 
 611                             } else if (withinService
) { 
 612                                 hasImeService 
|= actImeService
; 
 613                                 hasWallpaperService 
|= actWallpaperService
; 
 614                                 hasOtherServices 
|= (!actImeService 
&& !actWallpaperService
); 
 617                         withinIntentFilter 
= false; 
 621                 if (code 
!= ResXMLTree::START_TAG
) { 
 625                 String8 
tag(tree
.getElementName(&len
)); 
 626                 //printf("Depth %d,  %s\n", depth, tag.string()); 
 628                     if (tag 
!= "manifest") { 
 629                         fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n"); 
 632                     pkg 
= getAttribute(tree
, NULL
, "package", NULL
); 
 633                     printf("package: name='%s' ", pkg
.string()); 
 634                     int32_t versionCode 
= getIntegerAttribute(tree
, VERSION_CODE_ATTR
, &error
); 
 636                         fprintf(stderr
, "ERROR getting 'android:versionCode' attribute: %s\n", error
.string()); 
 639                     if (versionCode 
> 0) { 
 640                         printf("versionCode='%d' ", versionCode
); 
 642                         printf("versionCode='' "); 
 644                     String8 versionName 
= getResolvedAttribute(&res
, tree
, VERSION_NAME_ATTR
, &error
); 
 646                         fprintf(stderr
, "ERROR getting 'android:versionName' attribute: %s\n", error
.string()); 
 649                     printf("versionName='%s'\n", versionName
.string()); 
 650                 } else if (depth 
== 2) { 
 651                     withinApplication 
= false; 
 652                     if (tag 
== "application") { 
 653                         withinApplication 
= true; 
 654                         String8 label 
= getResolvedAttribute(&res
, tree
, LABEL_ATTR
, &error
); 
 656                              fprintf(stderr
, "ERROR getting 'android:label' attribute: %s\n", error
.string()); 
 659                         printf("application: label='%s' ", label
.string()); 
 660                         String8 icon 
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
); 
 662                             fprintf(stderr
, "ERROR getting 'android:icon' attribute: %s\n", error
.string()); 
 665                         printf("icon='%s'\n", icon
.string()); 
 666                         int32_t testOnly 
= getIntegerAttribute(tree
, TEST_ONLY_ATTR
, &error
, 0); 
 668                             fprintf(stderr
, "ERROR getting 'android:testOnly' attribute: %s\n", error
.string()); 
 672                             printf("testOnly='%d'\n", testOnly
); 
 674                     } else if (tag 
== "uses-sdk") { 
 675                         int32_t code 
= getIntegerAttribute(tree
, MIN_SDK_VERSION_ATTR
, &error
); 
 678                             String8 name 
= getResolvedAttribute(&res
, tree
, MIN_SDK_VERSION_ATTR
, &error
); 
 680                                 fprintf(stderr
, "ERROR getting 'android:minSdkVersion' attribute: %s\n", 
 684                             if (name 
== "Donut") targetSdk 
= 4; 
 685                             printf("sdkVersion:'%s'\n", name
.string()); 
 686                         } else if (code 
!= -1) { 
 688                             printf("sdkVersion:'%d'\n", code
); 
 690                         code 
= getIntegerAttribute(tree
, MAX_SDK_VERSION_ATTR
, NULL
, -1); 
 692                             printf("maxSdkVersion:'%d'\n", code
); 
 694                         code 
= getIntegerAttribute(tree
, TARGET_SDK_VERSION_ATTR
, &error
); 
 697                             String8 name 
= getResolvedAttribute(&res
, tree
, TARGET_SDK_VERSION_ATTR
, &error
); 
 699                                 fprintf(stderr
, "ERROR getting 'android:targetSdkVersion' attribute: %s\n", 
 703                             if (name 
== "Donut" && targetSdk 
< 4) targetSdk 
= 4; 
 704                             printf("targetSdkVersion:'%s'\n", name
.string()); 
 705                         } else if (code 
!= -1) { 
 706                             if (targetSdk 
< code
) { 
 709                             printf("targetSdkVersion:'%d'\n", code
); 
 711                     } else if (tag 
== "uses-configuration") { 
 712                         int32_t reqTouchScreen 
= getIntegerAttribute(tree
, 
 713                                 REQ_TOUCH_SCREEN_ATTR
, NULL
, 0); 
 714                         int32_t reqKeyboardType 
= getIntegerAttribute(tree
, 
 715                                 REQ_KEYBOARD_TYPE_ATTR
, NULL
, 0); 
 716                         int32_t reqHardKeyboard 
= getIntegerAttribute(tree
, 
 717                                 REQ_HARD_KEYBOARD_ATTR
, NULL
, 0); 
 718                         int32_t reqNavigation 
= getIntegerAttribute(tree
, 
 719                                 REQ_NAVIGATION_ATTR
, NULL
, 0); 
 720                         int32_t reqFiveWayNav 
= getIntegerAttribute(tree
, 
 721                                 REQ_FIVE_WAY_NAV_ATTR
, NULL
, 0); 
 722                         printf("uses-configuration:"); 
 723                         if (reqTouchScreen 
!= 0) { 
 724                             printf(" reqTouchScreen='%d'", reqTouchScreen
); 
 726                         if (reqKeyboardType 
!= 0) { 
 727                             printf(" reqKeyboardType='%d'", reqKeyboardType
); 
 729                         if (reqHardKeyboard 
!= 0) { 
 730                             printf(" reqHardKeyboard='%d'", reqHardKeyboard
); 
 732                         if (reqNavigation 
!= 0) { 
 733                             printf(" reqNavigation='%d'", reqNavigation
); 
 735                         if (reqFiveWayNav 
!= 0) { 
 736                             printf(" reqFiveWayNav='%d'", reqFiveWayNav
); 
 739                     } else if (tag 
== "supports-density") { 
 740                         int32_t dens 
= getIntegerAttribute(tree
, DENSITY_ATTR
, &error
); 
 742                             fprintf(stderr
, "ERROR getting 'android:density' attribute: %s\n", 
 746                         printf("supports-density:'%d'\n", dens
); 
 747                     } else if (tag 
== "supports-screens") { 
 748                         smallScreen 
= getIntegerAttribute(tree
, 
 749                                 SMALL_SCREEN_ATTR
, NULL
, 1); 
 750                         normalScreen 
= getIntegerAttribute(tree
, 
 751                                 NORMAL_SCREEN_ATTR
, NULL
, 1); 
 752                         largeScreen 
= getIntegerAttribute(tree
, 
 753                                 LARGE_SCREEN_ATTR
, NULL
, 1); 
 754                     } else if (tag 
== "uses-feature") { 
 755                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 757                         if (name 
!= "" && error 
== "") { 
 758                             int req 
= getIntegerAttribute(tree
, 
 759                                     REQUIRED_ATTR
, NULL
, 1); 
 761                             if (name 
== "android.hardware.camera") { 
 762                                 specCameraFeature 
= true; 
 763                             } else if (name 
== "android.hardware.camera.autofocus") { 
 764                                 // these have no corresponding permission to check for, 
 765                                 // but should imply the foundational camera permission 
 766                                 reqCameraAutofocusFeature 
= reqCameraAutofocusFeature 
|| req
; 
 767                                 specCameraAutofocusFeature 
= true; 
 768                             } else if (req 
&& (name 
== "android.hardware.camera.flash")) { 
 769                                 // these have no corresponding permission to check for, 
 770                                 // but should imply the foundational camera permission 
 771                                 reqCameraFlashFeature 
= true; 
 772                             } else if (name 
== "android.hardware.location") { 
 773                                 specLocationFeature 
= true; 
 774                             } else if (name 
== "android.hardware.location.network") { 
 775                                 specNetworkLocFeature 
= true; 
 776                                 reqNetworkLocFeature 
= reqNetworkLocFeature 
|| req
; 
 777                             } else if (name 
== "android.hardware.location.gps") { 
 778                                 specGpsFeature 
= true; 
 779                                 reqGpsFeature 
= reqGpsFeature 
|| req
; 
 780                             } else if (name 
== "android.hardware.bluetooth") { 
 781                                 specBluetoothFeature 
= true; 
 782                             } else if (name 
== "android.hardware.touchscreen") { 
 783                                 specTouchscreenFeature 
= true; 
 784                             } else if (name 
== "android.hardware.touchscreen.multitouch") { 
 785                                 specMultitouchFeature 
= true; 
 786                             } else if (name 
== "android.hardware.touchscreen.multitouch.distinct") { 
 787                                 reqDistinctMultitouchFeature 
= reqDistinctMultitouchFeature 
|| req
; 
 788                             } else if (name 
== "android.hardware.microphone") { 
 789                                 specMicrophoneFeature 
= true; 
 790                             } else if (name 
== "android.hardware.wifi") { 
 791                                 specWiFiFeature 
= true; 
 792                             } else if (name 
== "android.hardware.telephony") { 
 793                                 specTelephonyFeature 
= true; 
 794                             } else if (req 
&& (name 
== "android.hardware.telephony.gsm" || 
 795                                                name 
== "android.hardware.telephony.cdma")) { 
 796                                 // these have no corresponding permission to check for, 
 797                                 // but should imply the foundational telephony permission 
 798                                 reqTelephonySubFeature 
= true; 
 800                             printf("uses-feature%s:'%s'\n", 
 801                                     req 
? "" : "-not-required", name
.string()); 
 803                             int vers 
= getIntegerAttribute(tree
, 
 804                                     GL_ES_VERSION_ATTR
, &error
); 
 806                                 printf("uses-gl-es:'0x%x'\n", vers
); 
 809                     } else if (tag 
== "uses-permission") { 
 810                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 811                         if (name 
!= "" && error 
== "") { 
 812                             if (name 
== "android.permission.CAMERA") { 
 813                                 hasCameraPermission 
= true; 
 814                             } else if (name 
== "android.permission.ACCESS_FINE_LOCATION") { 
 815                                 hasGpsPermission 
= true; 
 816                             } else if (name 
== "android.permission.ACCESS_MOCK_LOCATION") { 
 817                                 hasMockLocPermission 
= true; 
 818                             } else if (name 
== "android.permission.ACCESS_COARSE_LOCATION") { 
 819                                 hasCoarseLocPermission 
= true; 
 820                             } else if (name 
== "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" || 
 821                                        name 
== "android.permission.INSTALL_LOCATION_PROVIDER") { 
 822                                 hasGeneralLocPermission 
= true; 
 823                             } else if (name 
== "android.permission.BLUETOOTH" || 
 824                                        name 
== "android.permission.BLUETOOTH_ADMIN") { 
 825                                 hasBluetoothPermission 
= true; 
 826                             } else if (name 
== "android.permission.RECORD_AUDIO") { 
 827                                 hasRecordAudioPermission 
= true; 
 828                             } else if (name 
== "android.permission.ACCESS_WIFI_STATE" || 
 829                                        name 
== "android.permission.CHANGE_WIFI_STATE" || 
 830                                        name 
== "android.permission.CHANGE_WIFI_MULTICAST_STATE") { 
 831                                 hasWiFiPermission 
= true; 
 832                             } else if (name 
== "android.permission.CALL_PHONE" || 
 833                                        name 
== "android.permission.CALL_PRIVILEGED" || 
 834                                        name 
== "android.permission.MODIFY_PHONE_STATE" || 
 835                                        name 
== "android.permission.PROCESS_OUTGOING_CALLS" || 
 836                                        name 
== "android.permission.READ_SMS" || 
 837                                        name 
== "android.permission.RECEIVE_SMS" || 
 838                                        name 
== "android.permission.RECEIVE_MMS" || 
 839                                        name 
== "android.permission.RECEIVE_WAP_PUSH" || 
 840                                        name 
== "android.permission.SEND_SMS" || 
 841                                        name 
== "android.permission.WRITE_APN_SETTINGS" || 
 842                                        name 
== "android.permission.WRITE_SMS") { 
 843                                 hasTelephonyPermission 
= true; 
 845                             printf("uses-permission:'%s'\n", name
.string()); 
 847                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", 
 851                     } else if (tag 
== "original-package") { 
 852                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 853                         if (name 
!= "" && error 
== "") { 
 854                             printf("original-package:'%s'\n", name
.string()); 
 856                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", 
 861                 } else if (depth 
== 3 && withinApplication
) { 
 862                     withinActivity 
= false; 
 863                     withinReceiver 
= false; 
 864                     withinService 
= false; 
 865                     hasIntentFilter 
= false; 
 866                     if(tag 
== "activity") { 
 867                         withinActivity 
= true; 
 868                         activityName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 870                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", error
.string()); 
 874                         activityLabel 
= getResolvedAttribute(&res
, tree
, LABEL_ATTR
, &error
); 
 876                             fprintf(stderr
, "ERROR getting 'android:label' attribute: %s\n", error
.string()); 
 880                         activityIcon 
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
); 
 882                             fprintf(stderr
, "ERROR getting 'android:icon' attribute: %s\n", error
.string()); 
 885                     } else if (tag 
== "uses-library") { 
 886                         String8 libraryName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 888                             fprintf(stderr
, "ERROR getting 'android:name' attribute for uses-library: %s\n", error
.string()); 
 891                         int req 
= getIntegerAttribute(tree
, 
 892                                 REQUIRED_ATTR
, NULL
, 1); 
 893                         printf("uses-library%s:'%s'\n", 
 894                                 req 
? "" : "-not-required", libraryName
.string()); 
 895                     } else if (tag 
== "receiver") { 
 896                         withinReceiver 
= true; 
 897                         receiverName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 900                             fprintf(stderr
, "ERROR getting 'android:name' attribute for receiver: %s\n", error
.string()); 
 903                     } else if (tag 
== "service") { 
 904                         withinService 
= true; 
 905                         serviceName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 908                             fprintf(stderr
, "ERROR getting 'android:name' attribute for service: %s\n", error
.string()); 
 912                 } else if ((depth 
== 4) && (tag 
== "intent-filter")) { 
 913                     hasIntentFilter 
= true; 
 914                     withinIntentFilter 
= true; 
 915                     actMainActivity 
= actWidgetReceivers 
= actImeService 
= actWallpaperService 
= false; 
 916                 } else if ((depth 
== 5) && withinIntentFilter
){ 
 918                     if (tag 
== "action") { 
 919                         action 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 921                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", error
.string()); 
 924                         if (withinActivity
) { 
 925                             if (action 
== "android.intent.action.MAIN") { 
 926                                 isMainActivity 
= true; 
 927                                 actMainActivity 
= true; 
 929                         } else if (withinReceiver
) { 
 930                             if (action 
== "android.appwidget.action.APPWIDGET_UPDATE") { 
 931                                 actWidgetReceivers 
= true; 
 933                         } else if (withinService
) { 
 934                             if (action 
== "android.view.InputMethod") { 
 935                                 actImeService 
= true; 
 936                             } else if (action 
== "android.service.wallpaper.WallpaperService") { 
 937                                 actWallpaperService 
= true; 
 940                         if (action 
== "android.intent.action.SEARCH") { 
 945                     if (tag 
== "category") { 
 946                         String8 category 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 948                             fprintf(stderr
, "ERROR getting 'name' attribute: %s\n", error
.string()); 
 951                         if (withinActivity
) { 
 952                             if (category 
== "android.intent.category.LAUNCHER") { 
 953                                 isLauncherActivity 
= true; 
 960             /* The following blocks handle printing "inferred" uses-features, based 
 961              * on whether related features or permissions are used by the app. 
 962              * Note that the various spec*Feature variables denote whether the 
 963              * relevant tag was *present* in the AndroidManfest, not that it was 
 964              * present and set to true. 
 966             // Camera-related back-compatibility logic 
 967             if (!specCameraFeature
) { 
 968                 if (reqCameraFlashFeature 
|| reqCameraAutofocusFeature
) { 
 969                     // if app requested a sub-feature (autofocus or flash) and didn't 
 970                     // request the base camera feature, we infer that it meant to 
 971                     printf("uses-feature:'android.hardware.camera'\n"); 
 972                 } else if (hasCameraPermission
) { 
 973                     // if app wants to use camera but didn't request the feature, we infer  
 974                     // that it meant to, and further that it wants autofocus 
 975                     // (which was the 1.0 - 1.5 behavior) 
 976                     printf("uses-feature:'android.hardware.camera'\n"); 
 977                     if (!specCameraAutofocusFeature
) { 
 978                         printf("uses-feature:'android.hardware.camera.autofocus'\n"); 
 983             // Location-related back-compatibility logic 
 984             if (!specLocationFeature 
&& 
 985                 (hasMockLocPermission 
|| hasCoarseLocPermission 
|| hasGpsPermission 
|| 
 986                  hasGeneralLocPermission 
|| reqNetworkLocFeature 
|| reqGpsFeature
)) { 
 987                 // if app either takes a location-related permission or requests one of the 
 988                 // sub-features, we infer that it also meant to request the base location feature 
 989                 printf("uses-feature:'android.hardware.location'\n"); 
 991             if (!specGpsFeature 
&& hasGpsPermission
) { 
 992                 // if app takes GPS (FINE location) perm but does not request the GPS 
 993                 // feature, we infer that it meant to 
 994                 printf("uses-feature:'android.hardware.location.gps'\n"); 
 996             if (!specNetworkLocFeature 
&& hasCoarseLocPermission
) { 
 997                 // if app takes Network location (COARSE location) perm but does not request the 
 998                 // network location feature, we infer that it meant to 
 999                 printf("uses-feature:'android.hardware.location.network'\n"); 
1002             // Bluetooth-related compatibility logic 
1003             if (!specBluetoothFeature 
&& hasBluetoothPermission
) { 
1004                 // if app takes a Bluetooth permission but does not request the Bluetooth 
1005                 // feature, we infer that it meant to 
1006                 printf("uses-feature:'android.hardware.bluetooth'\n"); 
1009             // Microphone-related compatibility logic 
1010             if (!specMicrophoneFeature 
&& hasRecordAudioPermission
) { 
1011                 // if app takes the record-audio permission but does not request the microphone 
1012                 // feature, we infer that it meant to 
1013                 printf("uses-feature:'android.hardware.microphone'\n"); 
1016             // WiFi-related compatibility logic 
1017             if (!specWiFiFeature 
&& hasWiFiPermission
) { 
1018                 // if app takes one of the WiFi permissions but does not request the WiFi 
1019                 // feature, we infer that it meant to 
1020                 printf("uses-feature:'android.hardware.wifi'\n"); 
1023             // Telephony-related compatibility logic 
1024             if (!specTelephonyFeature 
&& (hasTelephonyPermission 
|| reqTelephonySubFeature
)) { 
1025                 // if app takes one of the telephony permissions or requests a sub-feature but 
1026                 // does not request the base telephony feature, we infer that it meant to 
1027                 printf("uses-feature:'android.hardware.telephony'\n"); 
1030             // Touchscreen-related back-compatibility logic 
1031             if (!specTouchscreenFeature
) { // not a typo! 
1032                 // all apps are presumed to require a touchscreen, unless they explicitly say 
1033                 // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> 
1034                 // Note that specTouchscreenFeature is true if the tag is present, regardless 
1035                 // of whether its value is true or false, so this is safe 
1036                 printf("uses-feature:'android.hardware.touchscreen'\n"); 
1038             if (!specMultitouchFeature 
&& reqDistinctMultitouchFeature
) { 
1039                 // if app takes one of the telephony permissions or requests a sub-feature but 
1040                 // does not request the base telephony feature, we infer that it meant to 
1041                 printf("uses-feature:'android.hardware.touchscreen.multitouch'\n"); 
1044             if (hasMainActivity
) { 
1047             if (hasWidgetReceivers
) { 
1048                 printf("app-widget\n"); 
1050             if (hasImeService
) { 
1053             if (hasWallpaperService
) { 
1054                 printf("wallpaper\n"); 
1056             if (hasOtherActivities
) { 
1057                 printf("other-activities\n"); 
1062             if (hasOtherReceivers
) { 
1063                 printf("other-receivers\n"); 
1065             if (hasOtherServices
) { 
1066                 printf("other-services\n"); 
1069             // Determine default values for any unspecified screen sizes, 
1070             // based on the target SDK of the package.  As of 4 (donut) 
1071             // the screen size support was introduced, so all default to 
1073             if (smallScreen 
> 0) { 
1074                 smallScreen 
= targetSdk 
>= 4 ? -1 : 0; 
1076             if (normalScreen 
> 0) { 
1079             if (largeScreen 
> 0) { 
1080                 largeScreen 
= targetSdk 
>= 4 ? -1 : 0; 
1082             printf("supports-screens:"); 
1083             if (smallScreen 
!= 0) printf(" 'small'"); 
1084             if (normalScreen 
!= 0) printf(" 'normal'"); 
1085             if (largeScreen 
!= 0) printf(" 'large'"); 
1089             Vector
<String8
> locales
; 
1090             res
.getLocales(&locales
); 
1091             const size_t NL 
= locales
.size(); 
1092             for (size_t i
=0; i
<NL
; i
++) { 
1093                 const char* localeStr 
=  locales
[i
].string(); 
1094                 if (localeStr 
== NULL 
|| strlen(localeStr
) == 0) { 
1095                     localeStr 
= "--_--"; 
1097                 printf(" '%s'", localeStr
); 
1101             Vector
<ResTable_config
> configs
; 
1102             res
.getConfigurations(&configs
); 
1103             SortedVector
<int> densities
; 
1104             const size_t NC 
= configs
.size(); 
1105             for (size_t i
=0; i
<NC
; i
++) { 
1106                 int dens 
= configs
[i
].density
; 
1107                 if (dens 
== 0) dens 
= 160; 
1108                 densities
.add(dens
); 
1111             printf("densities:"); 
1112             const size_t ND 
= densities
.size(); 
1113             for (size_t i
=0; i
<ND
; i
++) { 
1114                 printf(" '%d'", densities
[i
]); 
1118             AssetDir
* dir 
= assets
.openNonAssetDir(assetsCookie
, "lib"); 
1120                 if (dir
->getFileCount() > 0) { 
1121                     printf("native-code:"); 
1122                     for (size_t i
=0; i
<dir
->getFileCount(); i
++) { 
1123                         printf(" '%s'", dir
->getFileName(i
).string()); 
1129         } else if (strcmp("configurations", option
) == 0) { 
1130             Vector
<ResTable_config
> configs
; 
1131             res
.getConfigurations(&configs
); 
1132             const size_t N 
= configs
.size(); 
1133             for (size_t i
=0; i
<N
; i
++) { 
1134                 printf("%s\n", configs
[i
].toString().string()); 
1137             fprintf(stderr
, "ERROR: unknown dump option '%s'\n", option
); 
1148     return (result 
!= NO_ERROR
); 
1153  * Handle the "add" command, which wants to add files to a new or 
1154  * pre-existing archive. 
1156 int doAdd(Bundle
* bundle
) 
1158     ZipFile
* zip 
= NULL
; 
1159     status_t result 
= UNKNOWN_ERROR
; 
1160     const char* zipFileName
; 
1162     if (bundle
->getUpdate()) { 
1163         /* avoid confusion */ 
1164         fprintf(stderr
, "ERROR: can't use '-u' with add\n"); 
1168     if (bundle
->getFileSpecCount() < 1) { 
1169         fprintf(stderr
, "ERROR: must specify zip file name\n"); 
1172     zipFileName 
= bundle
->getFileSpecEntry(0); 
1174     if (bundle
->getFileSpecCount() < 2) { 
1175         fprintf(stderr
, "NOTE: nothing to do\n"); 
1179     zip 
= openReadWrite(zipFileName
, true); 
1181         fprintf(stderr
, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName
); 
1185     for (int i 
= 1; i 
< bundle
->getFileSpecCount(); i
++) { 
1186         const char* fileName 
= bundle
->getFileSpecEntry(i
); 
1188         if (strcasecmp(String8(fileName
).getPathExtension().string(), ".gz") == 0) { 
1189             printf(" '%s'... (from gzip)\n", fileName
); 
1190             result 
= zip
->addGzip(fileName
, String8(fileName
).getBasePath().string(), NULL
); 
1192             if (bundle
->getJunkPath()) { 
1193                 String8 storageName 
= String8(fileName
).getPathLeaf(); 
1194                 printf(" '%s' as '%s'...\n", fileName
, storageName
.string()); 
1195                 result 
= zip
->add(fileName
, storageName
.string(), 
1196                                   bundle
->getCompressionMethod(), NULL
); 
1198                 printf(" '%s'...\n", fileName
); 
1199                 result 
= zip
->add(fileName
, bundle
->getCompressionMethod(), NULL
); 
1202         if (result 
!= NO_ERROR
) { 
1203             fprintf(stderr
, "Unable to add '%s' to '%s'", bundle
->getFileSpecEntry(i
), zipFileName
); 
1204             if (result 
== NAME_NOT_FOUND
) 
1205                 fprintf(stderr
, ": file not found\n"); 
1206             else if (result 
== ALREADY_EXISTS
) 
1207                 fprintf(stderr
, ": already exists in archive\n"); 
1209                 fprintf(stderr
, "\n"); 
1218     return (result 
!= NO_ERROR
); 
1223  * Delete files from an existing archive. 
1225 int doRemove(Bundle
* bundle
) 
1227     ZipFile
* zip 
= NULL
; 
1228     status_t result 
= UNKNOWN_ERROR
; 
1229     const char* zipFileName
; 
1231     if (bundle
->getFileSpecCount() < 1) { 
1232         fprintf(stderr
, "ERROR: must specify zip file name\n"); 
1235     zipFileName 
= bundle
->getFileSpecEntry(0); 
1237     if (bundle
->getFileSpecCount() < 2) { 
1238         fprintf(stderr
, "NOTE: nothing to do\n"); 
1242     zip 
= openReadWrite(zipFileName
, false); 
1244         fprintf(stderr
, "ERROR: failed opening Zip archive '%s'\n", 
1249     for (int i 
= 1; i 
< bundle
->getFileSpecCount(); i
++) { 
1250         const char* fileName 
= bundle
->getFileSpecEntry(i
); 
1253         entry 
= zip
->getEntryByName(fileName
); 
1254         if (entry 
== NULL
) { 
1255             printf(" '%s' NOT FOUND\n", fileName
); 
1259         result 
= zip
->remove(entry
); 
1261         if (result 
!= NO_ERROR
) { 
1262             fprintf(stderr
, "Unable to delete '%s' from '%s'\n", 
1263                 bundle
->getFileSpecEntry(i
), zipFileName
); 
1268     /* update the archive */ 
1273     return (result 
!= NO_ERROR
); 
1278  * Package up an asset directory and associated application files. 
1280 int doPackage(Bundle
* bundle
) 
1282     const char* outputAPKFile
; 
1285     sp
<AaptAssets
> assets
; 
1288     // -c zz_ZZ means do pseudolocalization 
1289     ResourceFilter filter
; 
1290     err 
= filter
.parse(bundle
->getConfigurations()); 
1291     if (err 
!= NO_ERROR
) { 
1294     if (filter
.containsPseudo()) { 
1295         bundle
->setPseudolocalize(true); 
1298     N 
= bundle
->getFileSpecCount(); 
1299     if (N 
< 1 && bundle
->getResourceSourceDirs().size() == 0 && bundle
->getJarFiles().size() == 0 
1300             && bundle
->getAndroidManifestFile() == NULL 
&& bundle
->getAssetSourceDir() == NULL
) { 
1301         fprintf(stderr
, "ERROR: no input files\n"); 
1305     outputAPKFile 
= bundle
->getOutputAPKFile(); 
1307     // Make sure the filenames provided exist and are of the appropriate type. 
1308     if (outputAPKFile
) { 
1310         type 
= getFileType(outputAPKFile
); 
1311         if (type 
!= kFileTypeNonexistent 
&& type 
!= kFileTypeRegular
) { 
1313                 "ERROR: output file '%s' exists but is not regular file\n", 
1320     assets 
= new AaptAssets(); 
1321     err 
= assets
->slurpFromArgs(bundle
); 
1326     if (bundle
->getVerbose()) { 
1330     // If they asked for any files that need to be compiled, do so. 
1331     if (bundle
->getResourceSourceDirs().size() || bundle
->getAndroidManifestFile()) { 
1332         err 
= buildResources(bundle
, assets
); 
1338     // At this point we've read everything and processed everything.  From here 
1339     // on out it's just writing output files. 
1340     if (SourcePos::hasErrors()) { 
1344     // Write out R.java constants 
1345     if (assets
->getPackage() == assets
->getSymbolsPrivatePackage()) { 
1346         if (bundle
->getCustomPackage() == NULL
) { 
1347             err 
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), true); 
1349             const String8 
customPkg(bundle
->getCustomPackage()); 
1350             err 
= writeResourceSymbols(bundle
, assets
, customPkg
, true); 
1356         err 
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), false); 
1360         err 
= writeResourceSymbols(bundle
, assets
, assets
->getSymbolsPrivatePackage(), true); 
1366     // Write out the ProGuard file 
1367     err 
= writeProguardFile(bundle
, assets
); 
1373     if (outputAPKFile
) { 
1374         err 
= writeAPK(bundle
, assets
, String8(outputAPKFile
)); 
1375         if (err 
!= NO_ERROR
) { 
1376             fprintf(stderr
, "ERROR: packaging of '%s' failed\n", outputAPKFile
); 
1383     if (SourcePos::hasErrors()) { 
1384         SourcePos::printErrors(stderr
);