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