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