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