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