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