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