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