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