Command.cpp revision c2dea8daea2ae0001d56689d96ce1066012b7b40
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    const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie);
768    if (dynamicRefTable == NULL) {
769        fprintf(stderr, "ERROR: failed to find dynamic reference table for asset cookie %d\n",
770                assetsCookie);
771        return 1;
772    }
773
774    Asset* asset = NULL;
775
776    if (strcmp("resources", option) == 0) {
777#ifndef HAVE_ANDROID_OS
778        res.print(bundle->getValues());
779#endif
780
781    } else if (strcmp("strings", option) == 0) {
782        const ResStringPool* pool = res.getTableStringBlock(0);
783        printStringPool(pool);
784
785    } else if (strcmp("xmltree", option) == 0) {
786        if (bundle->getFileSpecCount() < 3) {
787            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
788            goto bail;
789        }
790
791        for (int i=2; i<bundle->getFileSpecCount(); i++) {
792            const char* resname = bundle->getFileSpecEntry(i);
793            ResXMLTree tree(dynamicRefTable);
794            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
795            if (asset == NULL) {
796                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
797                goto bail;
798            }
799
800            if (tree.setTo(asset->getBuffer(true),
801                           asset->getLength()) != NO_ERROR) {
802                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
803                goto bail;
804            }
805            tree.restart();
806            printXMLBlock(&tree);
807            tree.uninit();
808            delete asset;
809            asset = NULL;
810        }
811
812    } else if (strcmp("xmlstrings", option) == 0) {
813        if (bundle->getFileSpecCount() < 3) {
814            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
815            goto bail;
816        }
817
818        for (int i=2; i<bundle->getFileSpecCount(); i++) {
819            const char* resname = bundle->getFileSpecEntry(i);
820            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
821            if (asset == NULL) {
822                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
823                goto bail;
824            }
825
826            ResXMLTree tree(dynamicRefTable);
827            if (tree.setTo(asset->getBuffer(true),
828                           asset->getLength()) != NO_ERROR) {
829                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
830                goto bail;
831            }
832            printStringPool(&tree.getStrings());
833            delete asset;
834            asset = NULL;
835        }
836
837    } else {
838        asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER);
839        if (asset == NULL) {
840            fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
841            goto bail;
842        }
843
844        ResXMLTree tree(dynamicRefTable);
845        if (tree.setTo(asset->getBuffer(true),
846                       asset->getLength()) != NO_ERROR) {
847            fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
848            goto bail;
849        }
850        tree.restart();
851
852        if (strcmp("permissions", option) == 0) {
853            size_t len;
854            ResXMLTree::event_code_t code;
855            int depth = 0;
856            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
857                if (code == ResXMLTree::END_TAG) {
858                    depth--;
859                    continue;
860                }
861                if (code != ResXMLTree::START_TAG) {
862                    continue;
863                }
864                depth++;
865                const char16_t* ctag16 = tree.getElementName(&len);
866                if (ctag16 == NULL) {
867                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
868                    goto bail;
869                }
870                String8 tag(ctag16);
871                //printf("Depth %d tag %s\n", depth, tag.string());
872                if (depth == 1) {
873                    if (tag != "manifest") {
874                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
875                        goto bail;
876                    }
877                    String8 pkg = getAttribute(tree, NULL, "package", NULL);
878                    printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
879                } else if (depth == 2 && tag == "permission") {
880                    String8 error;
881                    String8 name = getAttribute(tree, NAME_ATTR, &error);
882                    if (error != "") {
883                        fprintf(stderr, "ERROR: %s\n", error.string());
884                        goto bail;
885                    }
886                    printf("permission: %s\n",
887                            ResTable::normalizeForOutput(name.string()).string());
888                } else if (depth == 2 && tag == "uses-permission") {
889                    String8 error;
890                    String8 name = getAttribute(tree, NAME_ATTR, &error);
891                    if (error != "") {
892                        fprintf(stderr, "ERROR: %s\n", error.string());
893                        goto bail;
894                    }
895                    printUsesPermission(name,
896                            getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
897                            getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
898                }
899            }
900        } else if (strcmp("badging", option) == 0) {
901            Vector<String8> locales;
902            res.getLocales(&locales);
903
904            Vector<ResTable_config> configs;
905            res.getConfigurations(&configs);
906            SortedVector<int> densities;
907            const size_t NC = configs.size();
908            for (size_t i=0; i<NC; i++) {
909                int dens = configs[i].density;
910                if (dens == 0) {
911                    dens = 160;
912                }
913                densities.add(dens);
914            }
915
916            size_t len;
917            ResXMLTree::event_code_t code;
918            int depth = 0;
919            String8 error;
920            bool withinActivity = false;
921            bool isMainActivity = false;
922            bool isLauncherActivity = false;
923            bool isLeanbackLauncherActivity = false;
924            bool isSearchable = false;
925            bool withinApplication = false;
926            bool withinSupportsInput = false;
927            bool withinFeatureGroup = false;
928            bool withinReceiver = false;
929            bool withinService = false;
930            bool withinProvider = false;
931            bool withinIntentFilter = false;
932            bool hasMainActivity = false;
933            bool hasOtherActivities = false;
934            bool hasOtherReceivers = false;
935            bool hasOtherServices = false;
936            bool hasIntentFilter = false;
937
938            bool hasWallpaperService = false;
939            bool hasImeService = false;
940            bool hasAccessibilityService = false;
941            bool hasPrintService = false;
942            bool hasWidgetReceivers = false;
943            bool hasDeviceAdminReceiver = false;
944            bool hasPaymentService = false;
945            bool hasDocumentsProvider = false;
946            bool hasCameraActivity = false;
947            bool hasCameraSecureActivity = false;
948            bool hasLauncher = false;
949            bool hasNotificationListenerService = false;
950            bool hasDreamService = false;
951
952            bool actMainActivity = false;
953            bool actWidgetReceivers = false;
954            bool actDeviceAdminEnabled = false;
955            bool actImeService = false;
956            bool actWallpaperService = false;
957            bool actAccessibilityService = false;
958            bool actPrintService = false;
959            bool actHostApduService = false;
960            bool actOffHostApduService = false;
961            bool actDocumentsProvider = false;
962            bool actNotificationListenerService = false;
963            bool actDreamService = false;
964            bool actCamera = false;
965            bool actCameraSecure = false;
966            bool catLauncher = false;
967            bool hasMetaHostPaymentCategory = false;
968            bool hasMetaOffHostPaymentCategory = false;
969
970            // These permissions are required by services implementing services
971            // the system binds to (IME, Accessibility, PrintServices, etc.)
972            bool hasBindDeviceAdminPermission = false;
973            bool hasBindInputMethodPermission = false;
974            bool hasBindAccessibilityServicePermission = false;
975            bool hasBindPrintServicePermission = false;
976            bool hasBindNfcServicePermission = false;
977            bool hasRequiredSafAttributes = false;
978            bool hasBindNotificationListenerServicePermission = false;
979            bool hasBindDreamServicePermission = false;
980
981            // These two implement the implicit permissions that are granted
982            // to pre-1.6 applications.
983            bool hasWriteExternalStoragePermission = false;
984            bool hasReadPhoneStatePermission = false;
985
986            // If an app requests write storage, they will also get read storage.
987            bool hasReadExternalStoragePermission = false;
988
989            // Implement transition to read and write call log.
990            bool hasReadContactsPermission = false;
991            bool hasWriteContactsPermission = false;
992            bool hasReadCallLogPermission = false;
993            bool hasWriteCallLogPermission = false;
994
995            // This next group of variables is used to implement a group of
996            // backward-compatibility heuristics necessitated by the addition of
997            // some new uses-feature constants in 2.1 and 2.2. In most cases, the
998            // heuristic is "if an app requests a permission but doesn't explicitly
999            // request the corresponding <uses-feature>, presume it's there anyway".
1000
1001            // 2.2 also added some other features that apps can request, but that
1002            // have no corresponding permission, so we cannot implement any
1003            // back-compatibility heuristic for them. The below are thus unnecessary
1004            // (but are retained here for documentary purposes.)
1005            //bool specCompassFeature = false;
1006            //bool specAccelerometerFeature = false;
1007            //bool specProximityFeature = false;
1008            //bool specAmbientLightFeature = false;
1009            //bool specLiveWallpaperFeature = false;
1010
1011            int targetSdk = 0;
1012            int smallScreen = 1;
1013            int normalScreen = 1;
1014            int largeScreen = 1;
1015            int xlargeScreen = 1;
1016            int anyDensity = 1;
1017            int requiresSmallestWidthDp = 0;
1018            int compatibleWidthLimitDp = 0;
1019            int largestWidthLimitDp = 0;
1020            String8 pkg;
1021            String8 activityName;
1022            String8 activityLabel;
1023            String8 activityIcon;
1024            String8 activityBanner;
1025            String8 receiverName;
1026            String8 serviceName;
1027            Vector<String8> supportedInput;
1028
1029            FeatureGroup commonFeatures;
1030            Vector<FeatureGroup> featureGroups;
1031            KeyedVector<String8, ImpliedFeature> impliedFeatures;
1032
1033            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1034                if (code == ResXMLTree::END_TAG) {
1035                    depth--;
1036                    if (depth < 2) {
1037                        if (withinSupportsInput && !supportedInput.isEmpty()) {
1038                            printf("supports-input: '");
1039                            const size_t N = supportedInput.size();
1040                            for (size_t i=0; i<N; i++) {
1041                                printf("%s", ResTable::normalizeForOutput(
1042                                        supportedInput[i].string()).string());
1043                                if (i != N - 1) {
1044                                    printf("' '");
1045                                } else {
1046                                    printf("'\n");
1047                                }
1048                            }
1049                            supportedInput.clear();
1050                        }
1051                        withinApplication = false;
1052                        withinSupportsInput = false;
1053                        withinFeatureGroup = false;
1054                    } else if (depth < 3) {
1055                        if (withinActivity && isMainActivity) {
1056                            String8 aName(getComponentName(pkg, activityName));
1057                            if (isLauncherActivity) {
1058                                printf("launchable-activity:");
1059                                if (aName.length() > 0) {
1060                                    printf(" name='%s' ",
1061                                            ResTable::normalizeForOutput(aName.string()).string());
1062                                }
1063                                printf(" label='%s' icon='%s'\n",
1064                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
1065                                        ResTable::normalizeForOutput(activityIcon.string()).string());
1066                            }
1067                            if (isLeanbackLauncherActivity) {
1068                                printf("leanback-launchable-activity:");
1069                                if (aName.length() > 0) {
1070                                    printf(" name='%s' ",
1071                                            ResTable::normalizeForOutput(aName.string()).string());
1072                                }
1073                                printf(" label='%s' icon='%s' banner='%s'\n",
1074                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
1075                                        ResTable::normalizeForOutput(activityIcon.string()).string(),
1076                                        ResTable::normalizeForOutput(activityBanner.string()).string());
1077                            }
1078                        }
1079                        if (!hasIntentFilter) {
1080                            hasOtherActivities |= withinActivity;
1081                            hasOtherReceivers |= withinReceiver;
1082                            hasOtherServices |= withinService;
1083                        } else {
1084                            if (withinService) {
1085                                hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
1086                                        hasBindNfcServicePermission);
1087                                hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
1088                                        hasBindNfcServicePermission);
1089                            }
1090                        }
1091                        withinActivity = false;
1092                        withinService = false;
1093                        withinReceiver = false;
1094                        withinProvider = false;
1095                        hasIntentFilter = false;
1096                        isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false;
1097                    } else if (depth < 4) {
1098                        if (withinIntentFilter) {
1099                            if (withinActivity) {
1100                                hasMainActivity |= actMainActivity;
1101                                hasLauncher |= catLauncher;
1102                                hasCameraActivity |= actCamera;
1103                                hasCameraSecureActivity |= actCameraSecure;
1104                                hasOtherActivities |= !actMainActivity && !actCamera && !actCameraSecure;
1105                            } else if (withinReceiver) {
1106                                hasWidgetReceivers |= actWidgetReceivers;
1107                                hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
1108                                        hasBindDeviceAdminPermission);
1109                                hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled);
1110                            } else if (withinService) {
1111                                hasImeService |= actImeService;
1112                                hasWallpaperService |= actWallpaperService;
1113                                hasAccessibilityService |= (actAccessibilityService &&
1114                                        hasBindAccessibilityServicePermission);
1115                                hasPrintService |= (actPrintService && hasBindPrintServicePermission);
1116                                hasNotificationListenerService |= actNotificationListenerService &&
1117                                        hasBindNotificationListenerServicePermission;
1118                                hasDreamService |= actDreamService && hasBindDreamServicePermission;
1119                                hasOtherServices |= (!actImeService && !actWallpaperService &&
1120                                        !actAccessibilityService && !actPrintService &&
1121                                        !actHostApduService && !actOffHostApduService &&
1122                                        !actNotificationListenerService);
1123                            } else if (withinProvider) {
1124                                hasDocumentsProvider |= actDocumentsProvider && hasRequiredSafAttributes;
1125                            }
1126                        }
1127                        withinIntentFilter = false;
1128                    }
1129                    continue;
1130                }
1131                if (code != ResXMLTree::START_TAG) {
1132                    continue;
1133                }
1134                depth++;
1135
1136                const char16_t* ctag16 = tree.getElementName(&len);
1137                if (ctag16 == NULL) {
1138                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
1139                    goto bail;
1140                }
1141                String8 tag(ctag16);
1142                //printf("Depth %d,  %s\n", depth, tag.string());
1143                if (depth == 1) {
1144                    if (tag != "manifest") {
1145                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
1146                        goto bail;
1147                    }
1148                    pkg = getAttribute(tree, NULL, "package", NULL);
1149                    printf("package: name='%s' ",
1150                            ResTable::normalizeForOutput(pkg.string()).string());
1151                    int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error);
1152                    if (error != "") {
1153                        fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string());
1154                        goto bail;
1155                    }
1156                    if (versionCode > 0) {
1157                        printf("versionCode='%d' ", versionCode);
1158                    } else {
1159                        printf("versionCode='' ");
1160                    }
1161                    String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error);
1162                    if (error != "") {
1163                        fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string());
1164                        goto bail;
1165                    }
1166                    printf("versionName='%s'\n",
1167                            ResTable::normalizeForOutput(versionName.string()).string());
1168                } else if (depth == 2) {
1169                    withinApplication = false;
1170                    if (tag == "application") {
1171                        withinApplication = true;
1172
1173                        String8 label;
1174                        const size_t NL = locales.size();
1175                        for (size_t i=0; i<NL; i++) {
1176                            const char* localeStr =  locales[i].string();
1177                            assets.setLocale(localeStr != NULL ? localeStr : "");
1178                            String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1179                            if (llabel != "") {
1180                                if (localeStr == NULL || strlen(localeStr) == 0) {
1181                                    label = llabel;
1182                                    printf("application-label:'%s'\n",
1183                                            ResTable::normalizeForOutput(llabel.string()).string());
1184                                } else {
1185                                    if (label == "") {
1186                                        label = llabel;
1187                                    }
1188                                    printf("application-label-%s:'%s'\n", localeStr,
1189                                           ResTable::normalizeForOutput(llabel.string()).string());
1190                                }
1191                            }
1192                        }
1193
1194                        ResTable_config tmpConfig = config;
1195                        const size_t ND = densities.size();
1196                        for (size_t i=0; i<ND; i++) {
1197                            tmpConfig.density = densities[i];
1198                            assets.setConfiguration(tmpConfig);
1199                            String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1200                            if (icon != "") {
1201                                printf("application-icon-%d:'%s'\n", densities[i],
1202                                        ResTable::normalizeForOutput(icon.string()).string());
1203                            }
1204                        }
1205                        assets.setConfiguration(config);
1206
1207                        String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1208                        if (error != "") {
1209                            fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
1210                            goto bail;
1211                        }
1212                        int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
1213                        if (error != "") {
1214                            fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
1215                            goto bail;
1216                        }
1217                        printf("application: label='%s' ",
1218                                ResTable::normalizeForOutput(label.string()).string());
1219                        printf("icon='%s'\n", ResTable::normalizeForOutput(icon.string()).string());
1220                        if (testOnly != 0) {
1221                            printf("testOnly='%d'\n", testOnly);
1222                        }
1223
1224                        int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0);
1225                        if (error != "") {
1226                            fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string());
1227                            goto bail;
1228                        }
1229                        if (debuggable != 0) {
1230                            printf("application-debuggable\n");
1231                        }
1232                    } else if (tag == "uses-sdk") {
1233                        int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
1234                        if (error != "") {
1235                            error = "";
1236                            String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
1237                            if (error != "") {
1238                                fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
1239                                        error.string());
1240                                goto bail;
1241                            }
1242                            if (name == "Donut") targetSdk = 4;
1243                            printf("sdkVersion:'%s'\n",
1244                                    ResTable::normalizeForOutput(name.string()).string());
1245                        } else if (code != -1) {
1246                            targetSdk = code;
1247                            printf("sdkVersion:'%d'\n", code);
1248                        }
1249                        code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1);
1250                        if (code != -1) {
1251                            printf("maxSdkVersion:'%d'\n", code);
1252                        }
1253                        code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
1254                        if (error != "") {
1255                            error = "";
1256                            String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
1257                            if (error != "") {
1258                                fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
1259                                        error.string());
1260                                goto bail;
1261                            }
1262                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
1263                            printf("targetSdkVersion:'%s'\n",
1264                                    ResTable::normalizeForOutput(name.string()).string());
1265                        } else if (code != -1) {
1266                            if (targetSdk < code) {
1267                                targetSdk = code;
1268                            }
1269                            printf("targetSdkVersion:'%d'\n", code);
1270                        }
1271                    } else if (tag == "uses-configuration") {
1272                        int32_t reqTouchScreen = getIntegerAttribute(tree,
1273                                REQ_TOUCH_SCREEN_ATTR, NULL, 0);
1274                        int32_t reqKeyboardType = getIntegerAttribute(tree,
1275                                REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
1276                        int32_t reqHardKeyboard = getIntegerAttribute(tree,
1277                                REQ_HARD_KEYBOARD_ATTR, NULL, 0);
1278                        int32_t reqNavigation = getIntegerAttribute(tree,
1279                                REQ_NAVIGATION_ATTR, NULL, 0);
1280                        int32_t reqFiveWayNav = getIntegerAttribute(tree,
1281                                REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
1282                        printf("uses-configuration:");
1283                        if (reqTouchScreen != 0) {
1284                            printf(" reqTouchScreen='%d'", reqTouchScreen);
1285                        }
1286                        if (reqKeyboardType != 0) {
1287                            printf(" reqKeyboardType='%d'", reqKeyboardType);
1288                        }
1289                        if (reqHardKeyboard != 0) {
1290                            printf(" reqHardKeyboard='%d'", reqHardKeyboard);
1291                        }
1292                        if (reqNavigation != 0) {
1293                            printf(" reqNavigation='%d'", reqNavigation);
1294                        }
1295                        if (reqFiveWayNav != 0) {
1296                            printf(" reqFiveWayNav='%d'", reqFiveWayNav);
1297                        }
1298                        printf("\n");
1299                    } else if (tag == "supports-input") {
1300                        withinSupportsInput = true;
1301                    } else if (tag == "supports-screens") {
1302                        smallScreen = getIntegerAttribute(tree,
1303                                SMALL_SCREEN_ATTR, NULL, 1);
1304                        normalScreen = getIntegerAttribute(tree,
1305                                NORMAL_SCREEN_ATTR, NULL, 1);
1306                        largeScreen = getIntegerAttribute(tree,
1307                                LARGE_SCREEN_ATTR, NULL, 1);
1308                        xlargeScreen = getIntegerAttribute(tree,
1309                                XLARGE_SCREEN_ATTR, NULL, 1);
1310                        anyDensity = getIntegerAttribute(tree,
1311                                ANY_DENSITY_ATTR, NULL, 1);
1312                        requiresSmallestWidthDp = getIntegerAttribute(tree,
1313                                REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0);
1314                        compatibleWidthLimitDp = getIntegerAttribute(tree,
1315                                COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0);
1316                        largestWidthLimitDp = getIntegerAttribute(tree,
1317                                LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0);
1318                    } else if (tag == "feature-group") {
1319                        withinFeatureGroup = true;
1320                        FeatureGroup group;
1321                        group.label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1322                        if (error != "") {
1323                            fprintf(stderr, "ERROR getting 'android:label' attribute:"
1324                                    " %s\n", error.string());
1325                            goto bail;
1326                        }
1327                        featureGroups.add(group);
1328
1329                    } else if (tag == "uses-feature") {
1330                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1331                        if (name != "" && error == "") {
1332                            int req = getIntegerAttribute(tree,
1333                                    REQUIRED_ATTR, NULL, 1);
1334
1335                            commonFeatures.features.add(name, req);
1336                            if (req) {
1337                                addParentFeatures(&commonFeatures, name);
1338                            }
1339                        } else {
1340                            int vers = getIntegerAttribute(tree,
1341                                    GL_ES_VERSION_ATTR, &error);
1342                            if (error == "") {
1343                                if (vers > commonFeatures.openGLESVersion) {
1344                                    commonFeatures.openGLESVersion = vers;
1345                                }
1346                            }
1347                        }
1348                    } else if (tag == "uses-permission") {
1349                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1350                        if (name != "" && error == "") {
1351                            if (name == "android.permission.CAMERA") {
1352                                addImpliedFeature(&impliedFeatures, "android.hardware.camera",
1353                                        String8::format("requested %s permission", name.string())
1354                                        .string());
1355                            } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
1356                                addImpliedFeature(&impliedFeatures, "android.hardware.location.gps",
1357                                        String8::format("requested %s permission", name.string())
1358                                        .string());
1359                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
1360                                        String8::format("requested %s permission", name.string())
1361                                        .string());
1362                            } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
1363                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
1364                                        String8::format("requested %s permission", name.string())
1365                                        .string());
1366                            } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
1367                                addImpliedFeature(&impliedFeatures, "android.hardware.location.network",
1368                                        String8::format("requested %s permission", name.string())
1369                                        .string());
1370                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
1371                                        String8::format("requested %s permission", name.string())
1372                                        .string());
1373                            } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
1374                                       name == "android.permission.INSTALL_LOCATION_PROVIDER") {
1375                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
1376                                        String8::format("requested %s permission", name.string())
1377                                        .string());
1378                            } else if (name == "android.permission.BLUETOOTH" ||
1379                                       name == "android.permission.BLUETOOTH_ADMIN") {
1380                                if (targetSdk > 4) {
1381                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
1382                                            String8::format("requested %s permission", name.string())
1383                                            .string());
1384                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
1385                                            "targetSdkVersion > 4");
1386                                }
1387                            } else if (name == "android.permission.RECORD_AUDIO") {
1388                                addImpliedFeature(&impliedFeatures, "android.hardware.microphone",
1389                                        String8::format("requested %s permission", name.string())
1390                                        .string());
1391                            } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
1392                                       name == "android.permission.CHANGE_WIFI_STATE" ||
1393                                       name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
1394                                addImpliedFeature(&impliedFeatures, "android.hardware.wifi",
1395                                        String8::format("requested %s permission", name.string())
1396                                        .string());
1397                            } else if (name == "android.permission.CALL_PHONE" ||
1398                                       name == "android.permission.CALL_PRIVILEGED" ||
1399                                       name == "android.permission.MODIFY_PHONE_STATE" ||
1400                                       name == "android.permission.PROCESS_OUTGOING_CALLS" ||
1401                                       name == "android.permission.READ_SMS" ||
1402                                       name == "android.permission.RECEIVE_SMS" ||
1403                                       name == "android.permission.RECEIVE_MMS" ||
1404                                       name == "android.permission.RECEIVE_WAP_PUSH" ||
1405                                       name == "android.permission.SEND_SMS" ||
1406                                       name == "android.permission.WRITE_APN_SETTINGS" ||
1407                                       name == "android.permission.WRITE_SMS") {
1408                                addImpliedFeature(&impliedFeatures, "android.hardware.telephony",
1409                                        String8("requested a telephony permission").string());
1410                            } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
1411                                hasWriteExternalStoragePermission = true;
1412                            } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
1413                                hasReadExternalStoragePermission = true;
1414                            } else if (name == "android.permission.READ_PHONE_STATE") {
1415                                hasReadPhoneStatePermission = true;
1416                            } else if (name == "android.permission.READ_CONTACTS") {
1417                                hasReadContactsPermission = true;
1418                            } else if (name == "android.permission.WRITE_CONTACTS") {
1419                                hasWriteContactsPermission = true;
1420                            } else if (name == "android.permission.READ_CALL_LOG") {
1421                                hasReadCallLogPermission = true;
1422                            } else if (name == "android.permission.WRITE_CALL_LOG") {
1423                                hasWriteCallLogPermission = true;
1424                            }
1425
1426                            printUsesPermission(name,
1427                                    getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
1428                                    getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
1429                       } else {
1430                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1431                                    error.string());
1432                            goto bail;
1433                        }
1434                    } else if (tag == "uses-package") {
1435                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1436                        if (name != "" && error == "") {
1437                            printf("uses-package:'%s'\n",
1438                                    ResTable::normalizeForOutput(name.string()).string());
1439                        } else {
1440                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1441                                    error.string());
1442                                goto bail;
1443                        }
1444                    } else if (tag == "original-package") {
1445                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1446                        if (name != "" && error == "") {
1447                            printf("original-package:'%s'\n",
1448                                    ResTable::normalizeForOutput(name.string()).string());
1449                        } else {
1450                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1451                                    error.string());
1452                                goto bail;
1453                        }
1454                    } else if (tag == "supports-gl-texture") {
1455                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1456                        if (name != "" && error == "") {
1457                            printf("supports-gl-texture:'%s'\n",
1458                                    ResTable::normalizeForOutput(name.string()).string());
1459                        } else {
1460                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1461                                    error.string());
1462                                goto bail;
1463                        }
1464                    } else if (tag == "compatible-screens") {
1465                        printCompatibleScreens(tree, &error);
1466                        if (error != "") {
1467                            fprintf(stderr, "ERROR getting compatible screens: %s\n",
1468                                    error.string());
1469                            goto bail;
1470                        }
1471                        depth--;
1472                    } else if (tag == "package-verifier") {
1473                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1474                        if (name != "" && error == "") {
1475                            String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error);
1476                            if (publicKey != "" && error == "") {
1477                                printf("package-verifier: name='%s' publicKey='%s'\n",
1478                                        ResTable::normalizeForOutput(name.string()).string(),
1479                                        ResTable::normalizeForOutput(publicKey.string()).string());
1480                            }
1481                        }
1482                    }
1483                } else if (depth == 3) {
1484                    withinActivity = false;
1485                    withinReceiver = false;
1486                    withinService = false;
1487                    withinProvider = false;
1488                    hasIntentFilter = false;
1489                    hasMetaHostPaymentCategory = false;
1490                    hasMetaOffHostPaymentCategory = false;
1491                    hasBindDeviceAdminPermission = false;
1492                    hasBindInputMethodPermission = false;
1493                    hasBindAccessibilityServicePermission = false;
1494                    hasBindPrintServicePermission = false;
1495                    hasBindNfcServicePermission = false;
1496                    hasRequiredSafAttributes = false;
1497                    hasBindNotificationListenerServicePermission = false;
1498                    hasBindDreamServicePermission = false;
1499                    if (withinApplication) {
1500                        if(tag == "activity") {
1501                            withinActivity = true;
1502                            activityName = getAttribute(tree, NAME_ATTR, &error);
1503                            if (error != "") {
1504                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1505                                        error.string());
1506                                goto bail;
1507                            }
1508
1509                            activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1510                            if (error != "") {
1511                                fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
1512                                        error.string());
1513                                goto bail;
1514                            }
1515
1516                            activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1517                            if (error != "") {
1518                                fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
1519                                        error.string());
1520                                goto bail;
1521                            }
1522
1523                            activityBanner = getResolvedAttribute(&res, tree, BANNER_ATTR, &error);
1524                            if (error != "") {
1525                                fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
1526                                        error.string());
1527                                goto bail;
1528                            }
1529
1530                            int32_t orien = getResolvedIntegerAttribute(&res, tree,
1531                                    SCREEN_ORIENTATION_ATTR, &error);
1532                            if (error == "") {
1533                                if (orien == 0 || orien == 6 || orien == 8) {
1534                                    // Requests landscape, sensorLandscape, or reverseLandscape.
1535                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.landscape",
1536                                            "one or more activities have specified a landscape orientation");
1537                                } else if (orien == 1 || orien == 7 || orien == 9) {
1538                                    // Requests portrait, sensorPortrait, or reversePortrait.
1539                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.portrait",
1540                                            "one or more activities have specified a portrait orientation");
1541                                }
1542                            }
1543                        } else if (tag == "uses-library") {
1544                            String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
1545                            if (error != "") {
1546                                fprintf(stderr,
1547                                        "ERROR getting 'android:name' attribute for uses-library"
1548                                        " %s\n", error.string());
1549                                goto bail;
1550                            }
1551                            int req = getIntegerAttribute(tree,
1552                                    REQUIRED_ATTR, NULL, 1);
1553                            printf("uses-library%s:'%s'\n",
1554                                    req ? "" : "-not-required", ResTable::normalizeForOutput(
1555                                            libraryName.string()).string());
1556                        } else if (tag == "receiver") {
1557                            withinReceiver = true;
1558                            receiverName = getAttribute(tree, NAME_ATTR, &error);
1559
1560                            if (error != "") {
1561                                fprintf(stderr,
1562                                        "ERROR getting 'android:name' attribute for receiver:"
1563                                        " %s\n", error.string());
1564                                goto bail;
1565                            }
1566
1567                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1568                            if (error == "") {
1569                                if (permission == "android.permission.BIND_DEVICE_ADMIN") {
1570                                    hasBindDeviceAdminPermission = true;
1571                                }
1572                            } else {
1573                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1574                                        " receiver '%s': %s\n", receiverName.string(), error.string());
1575                            }
1576                        } else if (tag == "service") {
1577                            withinService = true;
1578                            serviceName = getAttribute(tree, NAME_ATTR, &error);
1579
1580                            if (error != "") {
1581                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1582                                        "service:%s\n", error.string());
1583                                goto bail;
1584                            }
1585
1586                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1587                            if (error == "") {
1588                                if (permission == "android.permission.BIND_INPUT_METHOD") {
1589                                    hasBindInputMethodPermission = true;
1590                                } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
1591                                    hasBindAccessibilityServicePermission = true;
1592                                } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
1593                                    hasBindPrintServicePermission = true;
1594                                } else if (permission == "android.permission.BIND_NFC_SERVICE") {
1595                                    hasBindNfcServicePermission = true;
1596                                } else if (permission == "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
1597                                    hasBindNotificationListenerServicePermission = true;
1598                                } else if (permission == "android.permission.BIND_DREAM_SERVICE") {
1599                                    hasBindDreamServicePermission = true;
1600                                }
1601                            } else {
1602                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1603                                        " service '%s': %s\n", serviceName.string(), error.string());
1604                            }
1605                        } else if (tag == "provider") {
1606                            withinProvider = true;
1607
1608                            bool exported = getResolvedIntegerAttribute(&res, tree, EXPORTED_ATTR, &error);
1609                            if (error != "") {
1610                                fprintf(stderr, "ERROR getting 'android:exported' attribute for provider:"
1611                                        " %s\n", error.string());
1612                                goto bail;
1613                            }
1614
1615                            bool grantUriPermissions = getResolvedIntegerAttribute(&res, tree,
1616                                    GRANT_URI_PERMISSIONS_ATTR, &error);
1617                            if (error != "") {
1618                                fprintf(stderr, "ERROR getting 'android:grantUriPermissions' attribute for provider:"
1619                                        " %s\n", error.string());
1620                                goto bail;
1621                            }
1622
1623                            String8 permission = getResolvedAttribute(&res, tree, PERMISSION_ATTR, &error);
1624                            if (error != "") {
1625                                fprintf(stderr, "ERROR getting 'android:permission' attribute for provider:"
1626                                        " %s\n", error.string());
1627                                goto bail;
1628                            }
1629
1630                            hasRequiredSafAttributes |= exported && grantUriPermissions &&
1631                                permission == "android.permission.MANAGE_DOCUMENTS";
1632
1633                        } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
1634                            String8 metaDataName = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
1635                            if (error != "") {
1636                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1637                                        "meta-data:%s\n", error.string());
1638                                goto bail;
1639                            }
1640                            printf("meta-data: name='%s' ",
1641                                    ResTable::normalizeForOutput(metaDataName.string()).string());
1642                            printResolvedResourceAttribute(&res, tree, VALUE_ATTR, String8("value"),
1643                                    &error);
1644                            if (error != "") {
1645                                // Try looking for a RESOURCE_ATTR
1646                                error = "";
1647                                printResolvedResourceAttribute(&res, tree, RESOURCE_ATTR,
1648                                        String8("resource"), &error);
1649                                if (error != "") {
1650                                    fprintf(stderr, "ERROR getting 'android:value' or "
1651                                            "'android:resource' attribute for "
1652                                            "meta-data:%s\n", error.string());
1653                                    goto bail;
1654                                }
1655                            }
1656                            printf("\n");
1657                        } else if (withinSupportsInput && tag == "input-type") {
1658                            String8 name = getAttribute(tree, NAME_ATTR, &error);
1659                            if (name != "" && error == "") {
1660                                supportedInput.add(name);
1661                            } else {
1662                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1663                                        error.string());
1664                                goto bail;
1665                            }
1666                        }
1667                    } else if (withinFeatureGroup && tag == "uses-feature") {
1668                        FeatureGroup& top = featureGroups.editTop();
1669
1670                        String8 name = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
1671                        if (name != "" && error == "") {
1672                            int required = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
1673                            top.features.add(name, required);
1674                            if (required) {
1675                                addParentFeatures(&top, name);
1676                            }
1677
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