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