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