Command.cpp revision d3edfde51bd069a63e820282421d1a534fcf00ce
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'",
1167                            ResTable::normalizeForOutput(versionName.string()).string());
1168
1169                    String8 splitName = getAttribute(tree, NULL, "split", NULL);
1170                    if (!splitName.isEmpty()) {
1171                        printf(" split='%s'", ResTable::normalizeForOutput(
1172                                    splitName.string()).string());
1173                    }
1174                    printf("\n");
1175                } else if (depth == 2) {
1176                    withinApplication = false;
1177                    if (tag == "application") {
1178                        withinApplication = true;
1179
1180                        String8 label;
1181                        const size_t NL = locales.size();
1182                        for (size_t i=0; i<NL; i++) {
1183                            const char* localeStr =  locales[i].string();
1184                            assets.setLocale(localeStr != NULL ? localeStr : "");
1185                            String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1186                            if (llabel != "") {
1187                                if (localeStr == NULL || strlen(localeStr) == 0) {
1188                                    label = llabel;
1189                                    printf("application-label:'%s'\n",
1190                                            ResTable::normalizeForOutput(llabel.string()).string());
1191                                } else {
1192                                    if (label == "") {
1193                                        label = llabel;
1194                                    }
1195                                    printf("application-label-%s:'%s'\n", localeStr,
1196                                           ResTable::normalizeForOutput(llabel.string()).string());
1197                                }
1198                            }
1199                        }
1200
1201                        ResTable_config tmpConfig = config;
1202                        const size_t ND = densities.size();
1203                        for (size_t i=0; i<ND; i++) {
1204                            tmpConfig.density = densities[i];
1205                            assets.setConfiguration(tmpConfig);
1206                            String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1207                            if (icon != "") {
1208                                printf("application-icon-%d:'%s'\n", densities[i],
1209                                        ResTable::normalizeForOutput(icon.string()).string());
1210                            }
1211                        }
1212                        assets.setConfiguration(config);
1213
1214                        String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1215                        if (error != "") {
1216                            fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
1217                            goto bail;
1218                        }
1219                        int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
1220                        if (error != "") {
1221                            fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
1222                            goto bail;
1223                        }
1224                        printf("application: label='%s' ",
1225                                ResTable::normalizeForOutput(label.string()).string());
1226                        printf("icon='%s'\n", ResTable::normalizeForOutput(icon.string()).string());
1227                        if (testOnly != 0) {
1228                            printf("testOnly='%d'\n", testOnly);
1229                        }
1230
1231                        int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0);
1232                        if (error != "") {
1233                            fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string());
1234                            goto bail;
1235                        }
1236                        if (debuggable != 0) {
1237                            printf("application-debuggable\n");
1238                        }
1239                    } else if (tag == "uses-sdk") {
1240                        int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
1241                        if (error != "") {
1242                            error = "";
1243                            String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
1244                            if (error != "") {
1245                                fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
1246                                        error.string());
1247                                goto bail;
1248                            }
1249                            if (name == "Donut") targetSdk = 4;
1250                            printf("sdkVersion:'%s'\n",
1251                                    ResTable::normalizeForOutput(name.string()).string());
1252                        } else if (code != -1) {
1253                            targetSdk = code;
1254                            printf("sdkVersion:'%d'\n", code);
1255                        }
1256                        code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1);
1257                        if (code != -1) {
1258                            printf("maxSdkVersion:'%d'\n", code);
1259                        }
1260                        code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
1261                        if (error != "") {
1262                            error = "";
1263                            String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
1264                            if (error != "") {
1265                                fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
1266                                        error.string());
1267                                goto bail;
1268                            }
1269                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
1270                            printf("targetSdkVersion:'%s'\n",
1271                                    ResTable::normalizeForOutput(name.string()).string());
1272                        } else if (code != -1) {
1273                            if (targetSdk < code) {
1274                                targetSdk = code;
1275                            }
1276                            printf("targetSdkVersion:'%d'\n", code);
1277                        }
1278                    } else if (tag == "uses-configuration") {
1279                        int32_t reqTouchScreen = getIntegerAttribute(tree,
1280                                REQ_TOUCH_SCREEN_ATTR, NULL, 0);
1281                        int32_t reqKeyboardType = getIntegerAttribute(tree,
1282                                REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
1283                        int32_t reqHardKeyboard = getIntegerAttribute(tree,
1284                                REQ_HARD_KEYBOARD_ATTR, NULL, 0);
1285                        int32_t reqNavigation = getIntegerAttribute(tree,
1286                                REQ_NAVIGATION_ATTR, NULL, 0);
1287                        int32_t reqFiveWayNav = getIntegerAttribute(tree,
1288                                REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
1289                        printf("uses-configuration:");
1290                        if (reqTouchScreen != 0) {
1291                            printf(" reqTouchScreen='%d'", reqTouchScreen);
1292                        }
1293                        if (reqKeyboardType != 0) {
1294                            printf(" reqKeyboardType='%d'", reqKeyboardType);
1295                        }
1296                        if (reqHardKeyboard != 0) {
1297                            printf(" reqHardKeyboard='%d'", reqHardKeyboard);
1298                        }
1299                        if (reqNavigation != 0) {
1300                            printf(" reqNavigation='%d'", reqNavigation);
1301                        }
1302                        if (reqFiveWayNav != 0) {
1303                            printf(" reqFiveWayNav='%d'", reqFiveWayNav);
1304                        }
1305                        printf("\n");
1306                    } else if (tag == "supports-input") {
1307                        withinSupportsInput = true;
1308                    } else if (tag == "supports-screens") {
1309                        smallScreen = getIntegerAttribute(tree,
1310                                SMALL_SCREEN_ATTR, NULL, 1);
1311                        normalScreen = getIntegerAttribute(tree,
1312                                NORMAL_SCREEN_ATTR, NULL, 1);
1313                        largeScreen = getIntegerAttribute(tree,
1314                                LARGE_SCREEN_ATTR, NULL, 1);
1315                        xlargeScreen = getIntegerAttribute(tree,
1316                                XLARGE_SCREEN_ATTR, NULL, 1);
1317                        anyDensity = getIntegerAttribute(tree,
1318                                ANY_DENSITY_ATTR, NULL, 1);
1319                        requiresSmallestWidthDp = getIntegerAttribute(tree,
1320                                REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0);
1321                        compatibleWidthLimitDp = getIntegerAttribute(tree,
1322                                COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0);
1323                        largestWidthLimitDp = getIntegerAttribute(tree,
1324                                LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0);
1325                    } else if (tag == "feature-group") {
1326                        withinFeatureGroup = true;
1327                        FeatureGroup group;
1328                        group.label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1329                        if (error != "") {
1330                            fprintf(stderr, "ERROR getting 'android:label' attribute:"
1331                                    " %s\n", error.string());
1332                            goto bail;
1333                        }
1334                        featureGroups.add(group);
1335
1336                    } else if (tag == "uses-feature") {
1337                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1338                        if (name != "" && error == "") {
1339                            int req = getIntegerAttribute(tree,
1340                                    REQUIRED_ATTR, NULL, 1);
1341
1342                            commonFeatures.features.add(name, req);
1343                            if (req) {
1344                                addParentFeatures(&commonFeatures, name);
1345                            }
1346                        } else {
1347                            int vers = getIntegerAttribute(tree,
1348                                    GL_ES_VERSION_ATTR, &error);
1349                            if (error == "") {
1350                                if (vers > commonFeatures.openGLESVersion) {
1351                                    commonFeatures.openGLESVersion = vers;
1352                                }
1353                            }
1354                        }
1355                    } else if (tag == "uses-permission") {
1356                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1357                        if (name != "" && error == "") {
1358                            if (name == "android.permission.CAMERA") {
1359                                addImpliedFeature(&impliedFeatures, "android.hardware.camera",
1360                                        String8::format("requested %s permission", name.string())
1361                                        .string());
1362                            } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
1363                                addImpliedFeature(&impliedFeatures, "android.hardware.location.gps",
1364                                        String8::format("requested %s permission", name.string())
1365                                        .string());
1366                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
1367                                        String8::format("requested %s permission", name.string())
1368                                        .string());
1369                            } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
1370                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
1371                                        String8::format("requested %s permission", name.string())
1372                                        .string());
1373                            } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
1374                                addImpliedFeature(&impliedFeatures, "android.hardware.location.network",
1375                                        String8::format("requested %s permission", name.string())
1376                                        .string());
1377                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
1378                                        String8::format("requested %s permission", name.string())
1379                                        .string());
1380                            } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
1381                                       name == "android.permission.INSTALL_LOCATION_PROVIDER") {
1382                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
1383                                        String8::format("requested %s permission", name.string())
1384                                        .string());
1385                            } else if (name == "android.permission.BLUETOOTH" ||
1386                                       name == "android.permission.BLUETOOTH_ADMIN") {
1387                                if (targetSdk > 4) {
1388                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
1389                                            String8::format("requested %s permission", name.string())
1390                                            .string());
1391                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
1392                                            "targetSdkVersion > 4");
1393                                }
1394                            } else if (name == "android.permission.RECORD_AUDIO") {
1395                                addImpliedFeature(&impliedFeatures, "android.hardware.microphone",
1396                                        String8::format("requested %s permission", name.string())
1397                                        .string());
1398                            } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
1399                                       name == "android.permission.CHANGE_WIFI_STATE" ||
1400                                       name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
1401                                addImpliedFeature(&impliedFeatures, "android.hardware.wifi",
1402                                        String8::format("requested %s permission", name.string())
1403                                        .string());
1404                            } else if (name == "android.permission.CALL_PHONE" ||
1405                                       name == "android.permission.CALL_PRIVILEGED" ||
1406                                       name == "android.permission.MODIFY_PHONE_STATE" ||
1407                                       name == "android.permission.PROCESS_OUTGOING_CALLS" ||
1408                                       name == "android.permission.READ_SMS" ||
1409                                       name == "android.permission.RECEIVE_SMS" ||
1410                                       name == "android.permission.RECEIVE_MMS" ||
1411                                       name == "android.permission.RECEIVE_WAP_PUSH" ||
1412                                       name == "android.permission.SEND_SMS" ||
1413                                       name == "android.permission.WRITE_APN_SETTINGS" ||
1414                                       name == "android.permission.WRITE_SMS") {
1415                                addImpliedFeature(&impliedFeatures, "android.hardware.telephony",
1416                                        String8("requested a telephony permission").string());
1417                            } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
1418                                hasWriteExternalStoragePermission = true;
1419                            } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
1420                                hasReadExternalStoragePermission = true;
1421                            } else if (name == "android.permission.READ_PHONE_STATE") {
1422                                hasReadPhoneStatePermission = true;
1423                            } else if (name == "android.permission.READ_CONTACTS") {
1424                                hasReadContactsPermission = true;
1425                            } else if (name == "android.permission.WRITE_CONTACTS") {
1426                                hasWriteContactsPermission = true;
1427                            } else if (name == "android.permission.READ_CALL_LOG") {
1428                                hasReadCallLogPermission = true;
1429                            } else if (name == "android.permission.WRITE_CALL_LOG") {
1430                                hasWriteCallLogPermission = true;
1431                            }
1432
1433                            printUsesPermission(name,
1434                                    getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
1435                                    getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
1436                       } else {
1437                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1438                                    error.string());
1439                            goto bail;
1440                        }
1441                    } else if (tag == "uses-package") {
1442                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1443                        if (name != "" && error == "") {
1444                            printf("uses-package:'%s'\n",
1445                                    ResTable::normalizeForOutput(name.string()).string());
1446                        } else {
1447                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1448                                    error.string());
1449                                goto bail;
1450                        }
1451                    } else if (tag == "original-package") {
1452                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1453                        if (name != "" && error == "") {
1454                            printf("original-package:'%s'\n",
1455                                    ResTable::normalizeForOutput(name.string()).string());
1456                        } else {
1457                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1458                                    error.string());
1459                                goto bail;
1460                        }
1461                    } else if (tag == "supports-gl-texture") {
1462                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1463                        if (name != "" && error == "") {
1464                            printf("supports-gl-texture:'%s'\n",
1465                                    ResTable::normalizeForOutput(name.string()).string());
1466                        } else {
1467                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1468                                    error.string());
1469                                goto bail;
1470                        }
1471                    } else if (tag == "compatible-screens") {
1472                        printCompatibleScreens(tree, &error);
1473                        if (error != "") {
1474                            fprintf(stderr, "ERROR getting compatible screens: %s\n",
1475                                    error.string());
1476                            goto bail;
1477                        }
1478                        depth--;
1479                    } else if (tag == "package-verifier") {
1480                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1481                        if (name != "" && error == "") {
1482                            String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error);
1483                            if (publicKey != "" && error == "") {
1484                                printf("package-verifier: name='%s' publicKey='%s'\n",
1485                                        ResTable::normalizeForOutput(name.string()).string(),
1486                                        ResTable::normalizeForOutput(publicKey.string()).string());
1487                            }
1488                        }
1489                    }
1490                } else if (depth == 3) {
1491                    withinActivity = false;
1492                    withinReceiver = false;
1493                    withinService = false;
1494                    withinProvider = false;
1495                    hasIntentFilter = false;
1496                    hasMetaHostPaymentCategory = false;
1497                    hasMetaOffHostPaymentCategory = false;
1498                    hasBindDeviceAdminPermission = false;
1499                    hasBindInputMethodPermission = false;
1500                    hasBindAccessibilityServicePermission = false;
1501                    hasBindPrintServicePermission = false;
1502                    hasBindNfcServicePermission = false;
1503                    hasRequiredSafAttributes = false;
1504                    hasBindNotificationListenerServicePermission = false;
1505                    hasBindDreamServicePermission = false;
1506                    if (withinApplication) {
1507                        if(tag == "activity") {
1508                            withinActivity = true;
1509                            activityName = getAttribute(tree, NAME_ATTR, &error);
1510                            if (error != "") {
1511                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1512                                        error.string());
1513                                goto bail;
1514                            }
1515
1516                            activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1517                            if (error != "") {
1518                                fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
1519                                        error.string());
1520                                goto bail;
1521                            }
1522
1523                            activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1524                            if (error != "") {
1525                                fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
1526                                        error.string());
1527                                goto bail;
1528                            }
1529
1530                            activityBanner = getResolvedAttribute(&res, tree, BANNER_ATTR, &error);
1531                            if (error != "") {
1532                                fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
1533                                        error.string());
1534                                goto bail;
1535                            }
1536
1537                            int32_t orien = getResolvedIntegerAttribute(&res, tree,
1538                                    SCREEN_ORIENTATION_ATTR, &error);
1539                            if (error == "") {
1540                                if (orien == 0 || orien == 6 || orien == 8) {
1541                                    // Requests landscape, sensorLandscape, or reverseLandscape.
1542                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.landscape",
1543                                            "one or more activities have specified a landscape orientation");
1544                                } else if (orien == 1 || orien == 7 || orien == 9) {
1545                                    // Requests portrait, sensorPortrait, or reversePortrait.
1546                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.portrait",
1547                                            "one or more activities have specified a portrait orientation");
1548                                }
1549                            }
1550                        } else if (tag == "uses-library") {
1551                            String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
1552                            if (error != "") {
1553                                fprintf(stderr,
1554                                        "ERROR getting 'android:name' attribute for uses-library"
1555                                        " %s\n", error.string());
1556                                goto bail;
1557                            }
1558                            int req = getIntegerAttribute(tree,
1559                                    REQUIRED_ATTR, NULL, 1);
1560                            printf("uses-library%s:'%s'\n",
1561                                    req ? "" : "-not-required", ResTable::normalizeForOutput(
1562                                            libraryName.string()).string());
1563                        } else if (tag == "receiver") {
1564                            withinReceiver = true;
1565                            receiverName = getAttribute(tree, NAME_ATTR, &error);
1566
1567                            if (error != "") {
1568                                fprintf(stderr,
1569                                        "ERROR getting 'android:name' attribute for receiver:"
1570                                        " %s\n", error.string());
1571                                goto bail;
1572                            }
1573
1574                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1575                            if (error == "") {
1576                                if (permission == "android.permission.BIND_DEVICE_ADMIN") {
1577                                    hasBindDeviceAdminPermission = true;
1578                                }
1579                            } else {
1580                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1581                                        " receiver '%s': %s\n", receiverName.string(), error.string());
1582                            }
1583                        } else if (tag == "service") {
1584                            withinService = true;
1585                            serviceName = getAttribute(tree, NAME_ATTR, &error);
1586
1587                            if (error != "") {
1588                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1589                                        "service:%s\n", error.string());
1590                                goto bail;
1591                            }
1592
1593                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1594                            if (error == "") {
1595                                if (permission == "android.permission.BIND_INPUT_METHOD") {
1596                                    hasBindInputMethodPermission = true;
1597                                } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
1598                                    hasBindAccessibilityServicePermission = true;
1599                                } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
1600                                    hasBindPrintServicePermission = true;
1601                                } else if (permission == "android.permission.BIND_NFC_SERVICE") {
1602                                    hasBindNfcServicePermission = true;
1603                                } else if (permission == "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
1604                                    hasBindNotificationListenerServicePermission = true;
1605                                } else if (permission == "android.permission.BIND_DREAM_SERVICE") {
1606                                    hasBindDreamServicePermission = true;
1607                                }
1608                            } else {
1609                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1610                                        " service '%s': %s\n", serviceName.string(), error.string());
1611                            }
1612                        } else if (tag == "provider") {
1613                            withinProvider = true;
1614
1615                            bool exported = getResolvedIntegerAttribute(&res, tree, EXPORTED_ATTR, &error);
1616                            if (error != "") {
1617                                fprintf(stderr, "ERROR getting 'android:exported' attribute for provider:"
1618                                        " %s\n", error.string());
1619                                goto bail;
1620                            }
1621
1622                            bool grantUriPermissions = getResolvedIntegerAttribute(&res, tree,
1623                                    GRANT_URI_PERMISSIONS_ATTR, &error);
1624                            if (error != "") {
1625                                fprintf(stderr, "ERROR getting 'android:grantUriPermissions' attribute for provider:"
1626                                        " %s\n", error.string());
1627                                goto bail;
1628                            }
1629
1630                            String8 permission = getResolvedAttribute(&res, tree, PERMISSION_ATTR, &error);
1631                            if (error != "") {
1632                                fprintf(stderr, "ERROR getting 'android:permission' attribute for provider:"
1633                                        " %s\n", error.string());
1634                                goto bail;
1635                            }
1636
1637                            hasRequiredSafAttributes |= exported && grantUriPermissions &&
1638                                permission == "android.permission.MANAGE_DOCUMENTS";
1639
1640                        } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
1641                            String8 metaDataName = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
1642                            if (error != "") {
1643                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1644                                        "meta-data:%s\n", error.string());
1645                                goto bail;
1646                            }
1647                            printf("meta-data: name='%s' ",
1648                                    ResTable::normalizeForOutput(metaDataName.string()).string());
1649                            printResolvedResourceAttribute(&res, tree, VALUE_ATTR, String8("value"),
1650                                    &error);
1651                            if (error != "") {
1652                                // Try looking for a RESOURCE_ATTR
1653                                error = "";
1654                                printResolvedResourceAttribute(&res, tree, RESOURCE_ATTR,
1655                                        String8("resource"), &error);
1656                                if (error != "") {
1657                                    fprintf(stderr, "ERROR getting 'android:value' or "
1658                                            "'android:resource' attribute for "
1659                                            "meta-data:%s\n", error.string());
1660                                    goto bail;
1661                                }
1662                            }
1663                            printf("\n");
1664                        } else if (withinSupportsInput && tag == "input-type") {
1665                            String8 name = getAttribute(tree, NAME_ATTR, &error);
1666                            if (name != "" && error == "") {
1667                                supportedInput.add(name);
1668                            } else {
1669                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1670                                        error.string());
1671                                goto bail;
1672                            }
1673                        }
1674                    } else if (withinFeatureGroup && tag == "uses-feature") {
1675                        FeatureGroup& top = featureGroups.editTop();
1676
1677                        String8 name = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
1678                        if (name != "" && error == "") {
1679                            top.features.add(name, true);
1680                            addParentFeatures(&top, name);
1681                        } else {
1682                            int vers = getIntegerAttribute(tree, GL_ES_VERSION_ATTR, &error);
1683                            if (error == "") {
1684                                if (vers > top.openGLESVersion) {
1685                                    top.openGLESVersion = vers;
1686                                }
1687                            }
1688                        }
1689                    }
1690                } else if (depth == 4) {
1691                    if (tag == "intent-filter") {
1692                        hasIntentFilter = true;
1693                        withinIntentFilter = true;
1694                        actMainActivity = false;
1695                        actWidgetReceivers = false;
1696                        actImeService = false;
1697                        actWallpaperService = false;
1698                        actAccessibilityService = false;
1699                        actPrintService = false;
1700                        actDeviceAdminEnabled = false;
1701                        actHostApduService = false;
1702                        actOffHostApduService = false;
1703                        actDocumentsProvider = false;
1704                        actNotificationListenerService = false;
1705                        actDreamService = false;
1706                        actCamera = false;
1707                        actCameraSecure = false;
1708                        catLauncher = false;
1709                    } else if (withinService && tag == "meta-data") {
1710                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1711                        if (error != "") {
1712                            fprintf(stderr, "ERROR getting 'android:name' attribute for"
1713                                    " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
1714                            goto bail;
1715                        }
1716
1717                        if (name == "android.nfc.cardemulation.host_apdu_service" ||
1718                                name == "android.nfc.cardemulation.off_host_apdu_service") {
1719                            bool offHost = true;
1720                            if (name == "android.nfc.cardemulation.host_apdu_service") {
1721                                offHost = false;
1722                            }
1723
1724                            String8 xmlPath = getResolvedAttribute(&res, tree, RESOURCE_ATTR, &error);
1725                            if (error != "") {
1726                                fprintf(stderr, "ERROR getting 'android:resource' attribute for"
1727                                        " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
1728                                goto bail;
1729                            }
1730
1731                            Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
1732                                    offHost, &error);
1733                            if (error != "") {
1734                                fprintf(stderr, "ERROR getting AID category for service '%s'\n",
1735                                        serviceName.string());
1736                                goto bail;
1737                            }
1738
1739                            const size_t catLen = categories.size();
1740                            for (size_t i = 0; i < catLen; i++) {
1741                                bool paymentCategory = (categories[i] == "payment");
1742                                if (offHost) {
1743                                    hasMetaOffHostPaymentCategory |= paymentCategory;
1744                                } else {
1745                                    hasMetaHostPaymentCategory |= paymentCategory;
1746                                }
1747                            }
1748                        }
1749                    }
1750                } else if ((depth == 5) && withinIntentFilter) {
1751                    String8 action;
1752                    if (tag == "action") {
1753                        action = getAttribute(tree, NAME_ATTR, &error);
1754                        if (error != "") {
1755                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1756                                    error.string());
1757                            goto bail;
1758                        }
1759
1760                        if (withinActivity) {
1761                            if (action == "android.intent.action.MAIN") {
1762                                isMainActivity = true;
1763                                actMainActivity = true;
1764                            } else if (action == "android.media.action.STILL_IMAGE_CAMERA" ||
1765                                    action == "android.media.action.VIDEO_CAMERA") {
1766                                actCamera = true;
1767                            } else if (action == "android.media.action.STILL_IMAGE_CAMERA_SECURE") {
1768                                actCameraSecure = true;
1769                            }
1770                        } else if (withinReceiver) {
1771                            if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
1772                                actWidgetReceivers = true;
1773                            } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
1774                                actDeviceAdminEnabled = true;
1775                            }
1776                        } else if (withinService) {
1777                            if (action == "android.view.InputMethod") {
1778                                actImeService = true;
1779                            } else if (action == "android.service.wallpaper.WallpaperService") {
1780                                actWallpaperService = true;
1781                            } else if (action == "android.accessibilityservice.AccessibilityService") {
1782                                actAccessibilityService = true;
1783                            } else if (action == "android.printservice.PrintService") {
1784                                actPrintService = true;
1785                            } else if (action == "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
1786                                actHostApduService = true;
1787                            } else if (action == "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
1788                                actOffHostApduService = true;
1789                            } else if (action == "android.service.notification.NotificationListenerService") {
1790                                actNotificationListenerService = true;
1791                            } else if (action == "android.service.dreams.DreamService") {
1792                                actDreamService = true;
1793                            }
1794                        } else if (withinProvider) {
1795                            if (action == "android.content.action.DOCUMENTS_PROVIDER") {
1796                                actDocumentsProvider = true;
1797                            }
1798                        }
1799                        if (action == "android.intent.action.SEARCH") {
1800                            isSearchable = true;
1801                        }
1802                    }
1803
1804                    if (tag == "category") {
1805                        String8 category = getAttribute(tree, NAME_ATTR, &error);
1806                        if (error != "") {
1807                            fprintf(stderr, "ERROR getting 'name' attribute: %s\n",
1808                                    error.string());
1809                            goto bail;
1810                        }
1811                        if (withinActivity) {
1812                            if (category == "android.intent.category.LAUNCHER") {
1813                                isLauncherActivity = true;
1814                            } else if (category == "android.intent.category.LEANBACK_LAUNCHER") {
1815                                isLeanbackLauncherActivity = true;
1816                            } else if (category == "android.intent.category.HOME") {
1817                                catLauncher = true;
1818                            }
1819                        }
1820                    }
1821                }
1822            }
1823
1824            // Pre-1.6 implicitly granted permission compatibility logic
1825            if (targetSdk < 4) {
1826                if (!hasWriteExternalStoragePermission) {
1827                    printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
1828                    printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
1829                            String8("targetSdkVersion < 4"));
1830                    hasWriteExternalStoragePermission = true;
1831                }
1832                if (!hasReadPhoneStatePermission) {
1833                    printUsesPermission(String8("android.permission.READ_PHONE_STATE"));
1834                    printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"),
1835                            String8("targetSdkVersion < 4"));
1836                }
1837            }
1838
1839            // If the application has requested WRITE_EXTERNAL_STORAGE, we will
1840            // force them to always take READ_EXTERNAL_STORAGE as well.  We always
1841            // do this (regardless of target API version) because we can't have
1842            // an app with write permission but not read permission.
1843            if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
1844                printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"));
1845                printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
1846                        String8("requested WRITE_EXTERNAL_STORAGE"));
1847            }
1848
1849            // Pre-JellyBean call log permission compatibility.
1850            if (targetSdk < 16) {
1851                if (!hasReadCallLogPermission && hasReadContactsPermission) {
1852                    printUsesPermission(String8("android.permission.READ_CALL_LOG"));
1853                    printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
1854                            String8("targetSdkVersion < 16 and requested READ_CONTACTS"));
1855                }
1856                if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
1857                    printUsesPermission(String8("android.permission.WRITE_CALL_LOG"));
1858                    printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"),
1859                            String8("targetSdkVersion < 16 and requested WRITE_CONTACTS"));
1860                }
1861            }
1862
1863            addImpliedFeature(&impliedFeatures, "android.hardware.touchscreen",
1864                    "default feature for all apps");
1865
1866            const size_t numFeatureGroups = featureGroups.size();
1867            if (numFeatureGroups == 0) {
1868                // If no <feature-group> tags were defined, apply auto-implied features.
1869                printFeatureGroup(commonFeatures, &impliedFeatures);
1870
1871            } else {
1872                // <feature-group> tags are defined, so we ignore implied features and
1873                for (size_t i = 0; i < numFeatureGroups; i++) {
1874                    FeatureGroup& grp = featureGroups.editItemAt(i);
1875
1876                    if (commonFeatures.openGLESVersion > grp.openGLESVersion) {
1877                        grp.openGLESVersion = commonFeatures.openGLESVersion;
1878                    }
1879
1880                    // Merge the features defined in the top level (not inside a <feature-group>)
1881                    // with this feature group.
1882                    const size_t numCommonFeatures = commonFeatures.features.size();
1883                    for (size_t j = 0; j < numCommonFeatures; j++) {
1884                        if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) {
1885                            grp.features.add(commonFeatures.features.keyAt(j),
1886                                    commonFeatures.features[j]);
1887                        }
1888                    }
1889
1890                   if (!grp.features.isEmpty()) {
1891                        printFeatureGroup(grp);
1892                    }
1893                }
1894            }
1895
1896
1897            if (hasWidgetReceivers) {
1898                printComponentPresence("app-widget");
1899            }
1900            if (hasDeviceAdminReceiver) {
1901                printComponentPresence("device-admin");
1902            }
1903            if (hasImeService) {
1904                printComponentPresence("ime");
1905            }
1906            if (hasWallpaperService) {
1907                printComponentPresence("wallpaper");
1908            }
1909            if (hasAccessibilityService) {
1910                printComponentPresence("accessibility");
1911            }
1912            if (hasPrintService) {
1913                printComponentPresence("print-service");
1914            }
1915            if (hasPaymentService) {
1916                printComponentPresence("payment");
1917            }
1918            if (isSearchable) {
1919                printComponentPresence("search");
1920            }
1921            if (hasDocumentsProvider) {
1922                printComponentPresence("document-provider");
1923            }
1924            if (hasLauncher) {
1925                printComponentPresence("launcher");
1926            }
1927            if (hasNotificationListenerService) {
1928                printComponentPresence("notification-listener");
1929            }
1930            if (hasDreamService) {
1931                printComponentPresence("dream");
1932            }
1933            if (hasCameraActivity) {
1934                printComponentPresence("camera");
1935            }
1936            if (hasCameraSecureActivity) {
1937                printComponentPresence("camera-secure");
1938            }
1939
1940            if (hasMainActivity) {
1941                printf("main\n");
1942            }
1943            if (hasOtherActivities) {
1944                printf("other-activities\n");
1945            }
1946             if (hasOtherReceivers) {
1947                printf("other-receivers\n");
1948            }
1949            if (hasOtherServices) {
1950                printf("other-services\n");
1951            }
1952
1953            // For modern apps, if screen size buckets haven't been specified
1954            // but the new width ranges have, then infer the buckets from them.
1955            if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
1956                    && requiresSmallestWidthDp > 0) {
1957                int compatWidth = compatibleWidthLimitDp;
1958                if (compatWidth <= 0) {
1959                    compatWidth = requiresSmallestWidthDp;
1960                }
1961                if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
1962                    smallScreen = -1;
1963                } else {
1964                    smallScreen = 0;
1965                }
1966                if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
1967                    normalScreen = -1;
1968                } else {
1969                    normalScreen = 0;
1970                }
1971                if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
1972                    largeScreen = -1;
1973                } else {
1974                    largeScreen = 0;
1975                }
1976                if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
1977                    xlargeScreen = -1;
1978                } else {
1979                    xlargeScreen = 0;
1980                }
1981            }
1982
1983            // Determine default values for any unspecified screen sizes,
1984            // based on the target SDK of the package.  As of 4 (donut)
1985            // the screen size support was introduced, so all default to
1986            // enabled.
1987            if (smallScreen > 0) {
1988                smallScreen = targetSdk >= 4 ? -1 : 0;
1989            }
1990            if (normalScreen > 0) {
1991                normalScreen = -1;
1992            }
1993            if (largeScreen > 0) {
1994                largeScreen = targetSdk >= 4 ? -1 : 0;
1995            }
1996            if (xlargeScreen > 0) {
1997                // Introduced in Gingerbread.
1998                xlargeScreen = targetSdk >= 9 ? -1 : 0;
1999            }
2000            if (anyDensity > 0) {
2001                anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
2002                        || compatibleWidthLimitDp > 0) ? -1 : 0;
2003            }
2004            printf("supports-screens:");
2005            if (smallScreen != 0) {
2006                printf(" 'small'");
2007            }
2008            if (normalScreen != 0) {
2009                printf(" 'normal'");
2010            }
2011            if (largeScreen != 0) {
2012                printf(" 'large'");
2013            }
2014            if (xlargeScreen != 0) {
2015                printf(" 'xlarge'");
2016            }
2017            printf("\n");
2018            printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
2019            if (requiresSmallestWidthDp > 0) {
2020                printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
2021            }
2022            if (compatibleWidthLimitDp > 0) {
2023                printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
2024            }
2025            if (largestWidthLimitDp > 0) {
2026                printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
2027            }
2028
2029            printf("locales:");
2030            const size_t NL = locales.size();
2031            for (size_t i=0; i<NL; i++) {
2032                const char* localeStr =  locales[i].string();
2033                if (localeStr == NULL || strlen(localeStr) == 0) {
2034                    localeStr = "--_--";
2035                }
2036                printf(" '%s'", localeStr);
2037            }
2038            printf("\n");
2039
2040            printf("densities:");
2041            const size_t ND = densities.size();
2042            for (size_t i=0; i<ND; i++) {
2043                printf(" '%d'", densities[i]);
2044            }
2045            printf("\n");
2046
2047            AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
2048            if (dir != NULL) {
2049                if (dir->getFileCount() > 0) {
2050                    printf("native-code:");
2051                    for (size_t i=0; i<dir->getFileCount(); i++) {
2052                        printf(" '%s'", ResTable::normalizeForOutput(
2053                                dir->getFileName(i).string()).string());
2054                    }
2055                    printf("\n");
2056                }
2057                delete dir;
2058            }
2059        } else if (strcmp("badger", option) == 0) {
2060            printf("%s", CONSOLE_DATA);
2061        } else if (strcmp("configurations", option) == 0) {
2062            Vector<ResTable_config> configs;
2063            res.getConfigurations(&configs);
2064            const size_t N = configs.size();
2065            for (size_t i=0; i<N; i++) {
2066                printf("%s\n", configs[i].toString().string());
2067            }
2068        } else {
2069            fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
2070            goto bail;
2071        }
2072    }
2073
2074    result = NO_ERROR;
2075
2076bail:
2077    if (asset) {
2078        delete asset;
2079    }
2080    return (result != NO_ERROR);
2081}
2082
2083
2084/*
2085 * Handle the "add" command, which wants to add files to a new or
2086 * pre-existing archive.
2087 */
2088int doAdd(Bundle* bundle)
2089{
2090    ZipFile* zip = NULL;
2091    status_t result = UNKNOWN_ERROR;
2092    const char* zipFileName;
2093
2094    if (bundle->getUpdate()) {
2095        /* avoid confusion */
2096        fprintf(stderr, "ERROR: can't use '-u' with add\n");
2097        goto bail;
2098    }
2099
2100    if (bundle->getFileSpecCount() < 1) {
2101        fprintf(stderr, "ERROR: must specify zip file name\n");
2102        goto bail;
2103    }
2104    zipFileName = bundle->getFileSpecEntry(0);
2105
2106    if (bundle->getFileSpecCount() < 2) {
2107        fprintf(stderr, "NOTE: nothing to do\n");
2108        goto bail;
2109    }
2110
2111    zip = openReadWrite(zipFileName, true);
2112    if (zip == NULL) {
2113        fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
2114        goto bail;
2115    }
2116
2117    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2118        const char* fileName = bundle->getFileSpecEntry(i);
2119
2120        if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
2121            printf(" '%s'... (from gzip)\n", fileName);
2122            result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
2123        } else {
2124            if (bundle->getJunkPath()) {
2125                String8 storageName = String8(fileName).getPathLeaf();
2126                printf(" '%s' as '%s'...\n", fileName,
2127                        ResTable::normalizeForOutput(storageName.string()).string());
2128                result = zip->add(fileName, storageName.string(),
2129                                  bundle->getCompressionMethod(), NULL);
2130            } else {
2131                printf(" '%s'...\n", fileName);
2132                result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
2133            }
2134        }
2135        if (result != NO_ERROR) {
2136            fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
2137            if (result == NAME_NOT_FOUND) {
2138                fprintf(stderr, ": file not found\n");
2139            } else if (result == ALREADY_EXISTS) {
2140                fprintf(stderr, ": already exists in archive\n");
2141            } else {
2142                fprintf(stderr, "\n");
2143            }
2144            goto bail;
2145        }
2146    }
2147
2148    result = NO_ERROR;
2149
2150bail:
2151    delete zip;
2152    return (result != NO_ERROR);
2153}
2154
2155
2156/*
2157 * Delete files from an existing archive.
2158 */
2159int doRemove(Bundle* bundle)
2160{
2161    ZipFile* zip = NULL;
2162    status_t result = UNKNOWN_ERROR;
2163    const char* zipFileName;
2164
2165    if (bundle->getFileSpecCount() < 1) {
2166        fprintf(stderr, "ERROR: must specify zip file name\n");
2167        goto bail;
2168    }
2169    zipFileName = bundle->getFileSpecEntry(0);
2170
2171    if (bundle->getFileSpecCount() < 2) {
2172        fprintf(stderr, "NOTE: nothing to do\n");
2173        goto bail;
2174    }
2175
2176    zip = openReadWrite(zipFileName, false);
2177    if (zip == NULL) {
2178        fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
2179            zipFileName);
2180        goto bail;
2181    }
2182
2183    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2184        const char* fileName = bundle->getFileSpecEntry(i);
2185        ZipEntry* entry;
2186
2187        entry = zip->getEntryByName(fileName);
2188        if (entry == NULL) {
2189            printf(" '%s' NOT FOUND\n", fileName);
2190            continue;
2191        }
2192
2193        result = zip->remove(entry);
2194
2195        if (result != NO_ERROR) {
2196            fprintf(stderr, "Unable to delete '%s' from '%s'\n",
2197                bundle->getFileSpecEntry(i), zipFileName);
2198            goto bail;
2199        }
2200    }
2201
2202    /* update the archive */
2203    zip->flush();
2204
2205bail:
2206    delete zip;
2207    return (result != NO_ERROR);
2208}
2209
2210static status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
2211    const size_t numDirs = dir->getDirs().size();
2212    for (size_t i = 0; i < numDirs; i++) {
2213        bool ignore = ignoreConfig;
2214        const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
2215        const char* dirStr = subDir->getLeaf().string();
2216        if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
2217            ignore = true;
2218        }
2219        status_t err = addResourcesToBuilder(subDir, builder, ignore);
2220        if (err != NO_ERROR) {
2221            return err;
2222        }
2223    }
2224
2225    const size_t numFiles = dir->getFiles().size();
2226    for (size_t i = 0; i < numFiles; i++) {
2227        sp<AaptGroup> gp = dir->getFiles().valueAt(i);
2228        const size_t numConfigs = gp->getFiles().size();
2229        for (size_t j = 0; j < numConfigs; j++) {
2230            status_t err = NO_ERROR;
2231            if (ignoreConfig) {
2232                err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
2233            } else {
2234                err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
2235            }
2236            if (err != NO_ERROR) {
2237                fprintf(stderr, "Failed to add %s (%s) to builder.\n",
2238                        gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
2239                return err;
2240            }
2241        }
2242    }
2243    return NO_ERROR;
2244}
2245
2246static String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
2247    if (split->isBase()) {
2248        return original;
2249    }
2250
2251    String8 ext(original.getPathExtension());
2252    if (ext == String8(".apk")) {
2253        return String8::format("%s_%s%s",
2254                original.getBasePath().string(),
2255                split->getDirectorySafeName().string(),
2256                ext.string());
2257    }
2258
2259    return String8::format("%s_%s", original.string(),
2260            split->getDirectorySafeName().string());
2261}
2262
2263/*
2264 * Package up an asset directory and associated application files.
2265 */
2266int doPackage(Bundle* bundle)
2267{
2268    const char* outputAPKFile;
2269    int retVal = 1;
2270    status_t err;
2271    sp<AaptAssets> assets;
2272    int N;
2273    FILE* fp;
2274    String8 dependencyFile;
2275    sp<ApkBuilder> builder;
2276
2277    // -c en_XA or/and ar_XB means do pseudolocalization
2278    sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
2279    err = configFilter->parse(bundle->getConfigurations());
2280    if (err != NO_ERROR) {
2281        goto bail;
2282    }
2283    if (configFilter->containsPseudo()) {
2284        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
2285    }
2286    if (configFilter->containsPseudoBidi()) {
2287        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
2288    }
2289
2290    N = bundle->getFileSpecCount();
2291    if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
2292            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
2293        fprintf(stderr, "ERROR: no input files\n");
2294        goto bail;
2295    }
2296
2297    outputAPKFile = bundle->getOutputAPKFile();
2298
2299    // Make sure the filenames provided exist and are of the appropriate type.
2300    if (outputAPKFile) {
2301        FileType type;
2302        type = getFileType(outputAPKFile);
2303        if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
2304            fprintf(stderr,
2305                "ERROR: output file '%s' exists but is not regular file\n",
2306                outputAPKFile);
2307            goto bail;
2308        }
2309    }
2310
2311    // Load the assets.
2312    assets = new AaptAssets();
2313
2314    // Set up the resource gathering in assets if we're going to generate
2315    // dependency files. Every time we encounter a resource while slurping
2316    // the tree, we'll add it to these stores so we have full resource paths
2317    // to write to a dependency file.
2318    if (bundle->getGenDependencies()) {
2319        sp<FilePathStore> resPathStore = new FilePathStore;
2320        assets->setFullResPaths(resPathStore);
2321        sp<FilePathStore> assetPathStore = new FilePathStore;
2322        assets->setFullAssetPaths(assetPathStore);
2323    }
2324
2325    err = assets->slurpFromArgs(bundle);
2326    if (err < 0) {
2327        goto bail;
2328    }
2329
2330    if (bundle->getVerbose()) {
2331        assets->print(String8());
2332    }
2333
2334    // Create the ApkBuilder, which will collect the compiled files
2335    // to write to the final APK (or sets of APKs if we are building
2336    // a Split APK.
2337    builder = new ApkBuilder(configFilter);
2338
2339    // If we are generating a Split APK, find out which configurations to split on.
2340    if (bundle->getSplitConfigurations().size() > 0) {
2341        const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
2342        const size_t numSplits = splitStrs.size();
2343        for (size_t i = 0; i < numSplits; i++) {
2344            std::set<ConfigDescription> configs;
2345            if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
2346                fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
2347                goto bail;
2348            }
2349
2350            err = builder->createSplitForConfigs(configs);
2351            if (err != NO_ERROR) {
2352                goto bail;
2353            }
2354        }
2355    }
2356
2357    // If they asked for any fileAs that need to be compiled, do so.
2358    if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
2359        err = buildResources(bundle, assets, builder);
2360        if (err != 0) {
2361            goto bail;
2362        }
2363    }
2364
2365    // At this point we've read everything and processed everything.  From here
2366    // on out it's just writing output files.
2367    if (SourcePos::hasErrors()) {
2368        goto bail;
2369    }
2370
2371    // Update symbols with information about which ones are needed as Java symbols.
2372    assets->applyJavaSymbols();
2373    if (SourcePos::hasErrors()) {
2374        goto bail;
2375    }
2376
2377    // If we've been asked to generate a dependency file, do that here
2378    if (bundle->getGenDependencies()) {
2379        // If this is the packaging step, generate the dependency file next to
2380        // the output apk (e.g. bin/resources.ap_.d)
2381        if (outputAPKFile) {
2382            dependencyFile = String8(outputAPKFile);
2383            // Add the .d extension to the dependency file.
2384            dependencyFile.append(".d");
2385        } else {
2386            // Else if this is the R.java dependency generation step,
2387            // generate the dependency file in the R.java package subdirectory
2388            // e.g. gen/com/foo/app/R.java.d
2389            dependencyFile = String8(bundle->getRClassDir());
2390            dependencyFile.appendPath("R.java.d");
2391        }
2392        // Make sure we have a clean dependency file to start with
2393        fp = fopen(dependencyFile, "w");
2394        fclose(fp);
2395    }
2396
2397    // Write out R.java constants
2398    if (!assets->havePrivateSymbols()) {
2399        if (bundle->getCustomPackage() == NULL) {
2400            // Write the R.java file into the appropriate class directory
2401            // e.g. gen/com/foo/app/R.java
2402            err = writeResourceSymbols(bundle, assets, assets->getPackage(), true);
2403        } else {
2404            const String8 customPkg(bundle->getCustomPackage());
2405            err = writeResourceSymbols(bundle, assets, customPkg, true);
2406        }
2407        if (err < 0) {
2408            goto bail;
2409        }
2410        // If we have library files, we're going to write our R.java file into
2411        // the appropriate class directory for those libraries as well.
2412        // e.g. gen/com/foo/app/lib/R.java
2413        if (bundle->getExtraPackages() != NULL) {
2414            // Split on colon
2415            String8 libs(bundle->getExtraPackages());
2416            char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
2417            while (packageString != NULL) {
2418                // Write the R.java file out with the correct package name
2419                err = writeResourceSymbols(bundle, assets, String8(packageString), true);
2420                if (err < 0) {
2421                    goto bail;
2422                }
2423                packageString = strtok(NULL, ":");
2424            }
2425            libs.unlockBuffer();
2426        }
2427    } else {
2428        err = writeResourceSymbols(bundle, assets, assets->getPackage(), false);
2429        if (err < 0) {
2430            goto bail;
2431        }
2432        err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true);
2433        if (err < 0) {
2434            goto bail;
2435        }
2436    }
2437
2438    // Write out the ProGuard file
2439    err = writeProguardFile(bundle, assets);
2440    if (err < 0) {
2441        goto bail;
2442    }
2443
2444    // Write the apk
2445    if (outputAPKFile) {
2446        // Gather all resources and add them to the APK Builder. The builder will then
2447        // figure out which Split they belong in.
2448        err = addResourcesToBuilder(assets, builder);
2449        if (err != NO_ERROR) {
2450            goto bail;
2451        }
2452
2453        const Vector<sp<ApkSplit> >& splits = builder->getSplits();
2454        const size_t numSplits = splits.size();
2455        for (size_t i = 0; i < numSplits; i++) {
2456            const sp<ApkSplit>& split = splits[i];
2457            String8 outputPath = buildApkName(String8(outputAPKFile), split);
2458            err = writeAPK(bundle, outputPath, split);
2459            if (err != NO_ERROR) {
2460                fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
2461                goto bail;
2462            }
2463        }
2464    }
2465
2466    // If we've been asked to generate a dependency file, we need to finish up here.
2467    // the writeResourceSymbols and writeAPK functions have already written the target
2468    // half of the dependency file, now we need to write the prerequisites. (files that
2469    // the R.java file or .ap_ file depend on)
2470    if (bundle->getGenDependencies()) {
2471        // Now that writeResourceSymbols or writeAPK has taken care of writing
2472        // the targets to our dependency file, we'll write the prereqs
2473        fp = fopen(dependencyFile, "a+");
2474        fprintf(fp, " : ");
2475        bool includeRaw = (outputAPKFile != NULL);
2476        err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
2477        // Also manually add the AndroidManifeset since it's not under res/ or assets/
2478        // and therefore was not added to our pathstores during slurping
2479        fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
2480        fclose(fp);
2481    }
2482
2483    retVal = 0;
2484bail:
2485    if (SourcePos::hasErrors()) {
2486        SourcePos::printErrors(stderr);
2487    }
2488    return retVal;
2489}
2490
2491/*
2492 * Do PNG Crunching
2493 * PRECONDITIONS
2494 *  -S flag points to a source directory containing drawable* folders
2495 *  -C flag points to destination directory. The folder structure in the
2496 *     source directory will be mirrored to the destination (cache) directory
2497 *
2498 * POSTCONDITIONS
2499 *  Destination directory will be updated to match the PNG files in
2500 *  the source directory.
2501 */
2502int doCrunch(Bundle* bundle)
2503{
2504    fprintf(stdout, "Crunching PNG Files in ");
2505    fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
2506    fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
2507
2508    updatePreProcessedCache(bundle);
2509
2510    return NO_ERROR;
2511}
2512
2513/*
2514 * Do PNG Crunching on a single flag
2515 *  -i points to a single png file
2516 *  -o points to a single png output file
2517 */
2518int doSingleCrunch(Bundle* bundle)
2519{
2520    fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
2521    fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
2522
2523    String8 input(bundle->getSingleCrunchInputFile());
2524    String8 output(bundle->getSingleCrunchOutputFile());
2525
2526    if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
2527        // we can't return the status_t as it gets truncate to the lower 8 bits.
2528        return 42;
2529    }
2530
2531    return NO_ERROR;
2532}
2533
2534char CONSOLE_DATA[2925] = {
2535    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2536    32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2537    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2538    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2539    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
2540    86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
2541    62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2542    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2543    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
2544    81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
2545    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2546    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2547    32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
2548    59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2549    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2550    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
2551    59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
2552    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2553    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2554    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
2555    58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
2556    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2557    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2558    47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
2559    121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2560    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2561    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
2562    81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
2563    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2564    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2565    32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
2566    59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2567    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2568    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
2569    59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
2570    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2571    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2572    32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
2573    70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
2574    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2575    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2576    32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
2577    81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2578    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2579    32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
2580    81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
2581    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2582    32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
2583    59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
2584    60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2585    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
2586    61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
2587    61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
2588    46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2589    32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2590    59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
2591    109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
2592    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
2593    67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2594    59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
2595    61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
2596    32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
2597    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
2598    73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2599    59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2600    32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
2601    59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
2602    46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
2603    97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
2604    46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
2605    119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
2606    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
2607    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2608    32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
2609    119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2610    59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
2611    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2612    32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
2613    81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
2614    87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2615    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
2616    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
2617    45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
2618    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2619    32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2620    81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
2621    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2622    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
2623    59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
2624    59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2625    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2626    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
2627    81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
2628    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2629    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2630    32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2631    81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2632    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2633    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
2634    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
2635    32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2636    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2637    32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2638    81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
2639    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2640    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2641    58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
2642    61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2643    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2644    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
2645    81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
2646    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2647    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2648    32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2649    81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2650    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2651    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
2652    59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
2653    59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2654    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2655    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
2656    58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
2657    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2658    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2659    61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
2660    59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
2661    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
2662    32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
2663    32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
2664    61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2665    32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2666    32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
2667    59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
2668    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
2669    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
2670    59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
2671    59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2672    32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2673    32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2674    32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2675    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2676    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2677    46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
2678    46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2679    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2680    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
2681    59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
2682    59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2683    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2684    32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
2685    32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
2686    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2687    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
2688    59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
2689    59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2690    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2691    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
2692    32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
2693    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2694    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2695    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2696    32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2697    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10
2698  };
2699