Command.cpp revision 3921e87e6e67a063caa1987937d7944b24aef489
1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Copyright 2006 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Android Asset Packaging Tool main entry point.
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
6fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski#include "ApkBuilder.h"
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "Main.h"
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "Bundle.h"
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceFilter.h"
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceTable.h"
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "Images.h"
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "XMLNode.h"
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/Log.h>
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/threads.h>
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/List.h>
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/Errors.h>
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <fcntl.h>
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <errno.h>
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiusing namespace android;
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Show version info.  All the cool kids do it.
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doVersion(Bundle* bundle)
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 0) {
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("(ignoring extra arguments)\n");
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("Android Asset Packaging Tool, v0.2\n");
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 0;
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read only.  The call fails if the file doesn't exist.
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadOnly(const char* fileName)
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip;
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, ZipFile::kOpenReadOnly);
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result == NAME_NOT_FOUND) {
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' not found\n", fileName);
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (result == PERMISSION_DENIED) {
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fileName);
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read-write.  The file will be created if it doesn't
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * already exist and "okayToCreate" is set.
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadWrite(const char* fileName, bool okayToCreate)
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int flags;
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    flags = ZipFile::kOpenReadWrite;
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (okayToCreate) {
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        flags |= ZipFile::kOpenCreate;
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, flags);
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        zip = NULL;
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return a short string describing the compression method.
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiconst char* compressionName(int method)
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (method == ZipEntry::kCompressStored) {
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Stored";
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (method == ZipEntry::kCompressDeflated) {
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Deflated";
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Unknown";
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return the percent reduction in size (0% == no compression).
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint calcPercent(long uncompressedLen, long compressedLen)
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!uncompressedLen) {
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 0;
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "list" command, which can be a simple file dump or
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * a verbose listing.
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The verbose listing closely matches the output of the Info-ZIP "unzip"
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * command.
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doList(Bundle* bundle)
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int result = 1;
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ZipEntry* entry;
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    long totalUncLen, totalCompLen;
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 1) {
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: specify zip file name (only)\n");
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadOnly(zipFileName);
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int count, i;
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("Archive:  %s\n", zipFileName);
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            " Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name\n");
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            "--------  ------  ------- -----  -------      ----  ----  ------    ----\n");
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    totalUncLen = totalCompLen = 0;
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    count = zip->getNumEntries();
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i = 0; i < count; i++) {
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByIndex(i);
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getVerbose()) {
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char dateBuf[32];
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            time_t when;
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            when = entry->getModWhen();
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                localtime(&when));
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%8ld  %-7.7s %7ld %3d%%  %8zd  %s  %08lx  %s\n",
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getUncompressedLen(),
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                compressionName(entry->getCompressionMethod()),
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getCompressedLen(),
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                calcPercent(entry->getUncompressedLen(),
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            entry->getCompressedLen()),
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (size_t) entry->getLFHOffset(),
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                dateBuf,
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getCRC32(),
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getFileName());
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s\n", entry->getFileName());
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalUncLen += entry->getUncompressedLen();
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalCompLen += entry->getCompressedLen();
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "--------          -------  ---                            -------\n");
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("%8ld          %7ld  %2d%%                            %d files\n",
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalUncLen,
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalCompLen,
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            calcPercent(totalUncLen, totalCompLen),
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zip->getNumEntries());
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getAndroidList()) {
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        AssetManager assets;
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!assets.addAssetPath(String8(zipFileName), NULL)) {
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResTable& res = assets.getResources(false);
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (&res == NULL) {
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo resource table found.\n");
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nResource table:\n");
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.print(false);
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                   Asset::ACCESS_BUFFER);
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (manifestAsset == NULL) {
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo AndroidManifest.xml found.\n");
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nAndroid manifest:\n");
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree tree;
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.setTo(manifestAsset->getBuffer(true),
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       manifestAsset->getLength());
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete manifestAsset;
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = 0;
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes)
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t N = tree.getAttributeCount();
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.getAttributeNameResID(i) == attrRes) {
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return (ssize_t)i;
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return -1;
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiString8 getAttribute(const ResXMLTree& tree, const char* ns,
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char* attr, String8* outError)
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = tree.indexOfAttribute(ns, attr);
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError)
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes,
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String8* outError, int32_t defValue = -1)
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return defValue;
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType < Res_value::TYPE_FIRST_INT
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || value.dataType > Res_value::TYPE_LAST_INT) {
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not an integer value";
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return defValue;
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return value.data;
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree,
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t attrRes, String8* outError, int32_t defValue = -1)
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return defValue;
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType == Res_value::TYPE_REFERENCE) {
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            resTable->resolveReference(&value, 0);
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType < Res_value::TYPE_FIRST_INT
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || value.dataType > Res_value::TYPE_LAST_INT) {
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not an integer value";
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return defValue;
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return value.data;
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree,
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t attrRes, String8* outError)
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType == Res_value::TYPE_STRING) {
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const uint16_t* str = tree.getAttributeStringValue(idx, &len);
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return str ? String8(str, len) : String8();
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        resTable->resolveReference(&value, 0);
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const Res_value* value2 = &value;
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len);
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic void getResolvedResourceAttribute(Res_value* value, const ResTable* resTable,
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResXMLTree& tree, uint32_t attrRes, String8* outError)
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outError != NULL) {
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            *outError = "attribute could not be found";
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, value) != NO_ERROR) {
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value->dataType == Res_value::TYPE_REFERENCE) {
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            resTable->resolveReference(value, 0);
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // The attribute was found and was resolved if need be.
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outError != NULL) {
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *outError = "error getting resolved resource attribute";
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
38276327314d2238e105f8b94909f9c0cf85caca318Maurice Chustatic void printResolvedResourceAttribute(const ResTable* resTable, const ResXMLTree& tree,
38376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        uint32_t attrRes, String8 attrLabel, String8* outError)
38476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu{
38576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    Res_value value;
38676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    getResolvedResourceAttribute(&value, resTable, tree, attrRes, outError);
38776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (*outError != "") {
38876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        *outError = "error print resolved resource attribute";
38976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        return;
39076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
39176327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (value.dataType == Res_value::TYPE_STRING) {
39276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        String8 result = getResolvedAttribute(resTable, tree, attrRes, outError);
3932675f769673f69b0661ddee346292f25cb30a296Maurice Chu        printf("%s='%s'", attrLabel.string(),
3942675f769673f69b0661ddee346292f25cb30a296Maurice Chu                ResTable::normalizeForOutput(result.string()).string());
39576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
39676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu            value.dataType <= Res_value::TYPE_LAST_INT) {
39776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='%d'", attrLabel.string(), value.data);
39876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else {
39976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='0x%x'", attrLabel.string(), (int)value.data);
40076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
40176327314d2238e105f8b94909f9c0cf85caca318Maurice Chu}
40276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu
403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// These are attribute resource constants for the platform, as found
404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// in android.R.attr
405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskienum {
406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LABEL_ATTR = 0x01010001,
407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ICON_ATTR = 0x01010002,
408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NAME_ATTR = 0x01010003,
409a5018c900f126ee8424c82497f32983873db741bAdam Lesinski    PERMISSION_ATTR = 0x01010006,
41094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    RESOURCE_ATTR = 0x01010025,
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    DEBUGGABLE_ATTR = 0x0101000f,
412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VALUE_ATTR = 0x01010024,
413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_CODE_ATTR = 0x0101021b,
414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_NAME_ATTR = 0x0101021c,
415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_ORIENTATION_ATTR = 0x0101001e,
416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MIN_SDK_VERSION_ATTR = 0x0101020c,
417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MAX_SDK_VERSION_ATTR = 0x01010271,
418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_TOUCH_SCREEN_ATTR = 0x01010227,
419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_HARD_KEYBOARD_ATTR = 0x01010229,
421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_NAVIGATION_ATTR = 0x0101022a,
422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TARGET_SDK_VERSION_ATTR = 0x01010270,
424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TEST_ONLY_ATTR = 0x01010272,
425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ANY_DENSITY_ATTR = 0x0101026c,
426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    GL_ES_VERSION_ATTR = 0x01010281,
427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SMALL_SCREEN_ATTR = 0x01010284,
428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NORMAL_SCREEN_ATTR = 0x01010285,
429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGE_SCREEN_ATTR = 0x01010286,
430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    XLARGE_SCREEN_ATTR = 0x010102bf,
431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRED_ATTR = 0x0101028e,
432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_SIZE_ATTR = 0x010102ca,
433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_DENSITY_ATTR = 0x010102cb,
434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    PUBLIC_KEY_ATTR = 0x010103a6,
43894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    CATEGORY_ATTR = 0x010103e8,
4390a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn    BANNER_ATTR = 0x10103f2,
440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4422675f769673f69b0661ddee346292f25cb30a296Maurice ChuString8 getComponentName(String8 &pkgName, String8 &componentName) {
443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = componentName.find(".");
444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 retStr(pkgName);
445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx == 0) {
446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (idx < 0) {
448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += ".";
449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
4512675f769673f69b0661ddee346292f25cb30a296Maurice Chu        return componentName;
452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4532675f769673f69b0661ddee346292f25cb30a296Maurice Chu    return retStr;
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic void printCompatibleScreens(ResXMLTree& tree) {
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResXMLTree::event_code_t code;
459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int depth = 0;
460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool first = true;
461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("compatible-screens:");
462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code == ResXMLTree::END_TAG) {
464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            depth--;
465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (depth < 0) {
466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code != ResXMLTree::START_TAG) {
471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        depth++;
474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String8 tag(tree.getElementName(&len));
475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tag == "screen") {
476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int32_t screenSize = getIntegerAttribute(tree,
477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SCREEN_SIZE_ATTR, NULL, -1);
478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int32_t screenDensity = getIntegerAttribute(tree,
479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SCREEN_DENSITY_ATTR, NULL, -1);
480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (screenSize > 0 && screenDensity > 0) {
481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!first) {
482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf(",");
483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                first = false;
485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("'%d/%d'", screenSize, screenDensity);
486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("\n");
490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
49258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
49358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
49458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (maxSdkVersion != -1) {
49558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski         printf(" maxSdkVersion='%d'", maxSdkVersion);
49658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
49758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("\n");
49858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
49958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (optional) {
50058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("optional-permission: name='%s'",
50158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                ResTable::normalizeForOutput(name.string()).string());
50258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        if (maxSdkVersion != -1) {
50358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            printf(" maxSdkVersion='%d'", maxSdkVersion);
50458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        }
50558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("\n");
50658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
50758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
50858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
50958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesImpliedPermission(const String8& name, const String8& reason) {
51058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-implied-permission: name='%s' reason='%s'\n",
51158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(name.string()).string(),
51258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(reason.string()).string());
51358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
51458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
51594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam LesinskiVector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost,
51694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        String8 *outError = NULL)
51794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski{
51894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
51994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    if (aidAsset == NULL) {
52094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (outError != NULL) *outError = "xml resource does not exist";
52194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        return Vector<String8>();
52294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
52394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
52494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
52594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
52694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    bool withinApduService = false;
52794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Vector<String8> categories;
52894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
52994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    String8 error;
53094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree tree;
53194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
53294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
53394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    size_t len;
53494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    int depth = 0;
53594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree::event_code_t code;
53694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
53794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (code == ResXMLTree::END_TAG) {
53894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth--;
53994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            String8 tag(tree.getElementName(&len));
54094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
54194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 0 && tag == serviceTagName) {
54294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                withinApduService = false;
54394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
54494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
54594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        } else if (code == ResXMLTree::START_TAG) {
54694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth++;
54794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            String8 tag(tree.getElementName(&len));
54894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
54994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 1) {
55094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == serviceTagName) {
55194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    withinApduService = true;
55294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
55394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            } else if (depth == 2 && withinApduService) {
55494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == "aid-group") {
55594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    String8 category = getAttribute(tree, CATEGORY_ATTR, &error);
55694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (error != "") {
55794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (outError != NULL) *outError = error;
55894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        return Vector<String8>();
55994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
56094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
56194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    categories.add(category);
56294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
56394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
56494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        }
56594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
56694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    aidAsset->close();
56794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    return categories;
56894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski}
56994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "dump" command, to extract select data from an archive.
572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiextern char CONSOLE_DATA[2925]; // see EOF
574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doDump(Bundle* bundle)
575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Asset* asset = NULL;
578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump option specified\n");
581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump file specified\n");
586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* option = bundle->getFileSpecEntry(0);
590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* filename = bundle->getFileSpecEntry(1);
591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    AssetManager assets;
593f85e41f29a0e9313c2d4725f9d9648591ea49f3bNarayan Kamath    int32_t assetsCookie;
594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make a dummy config for retrieving resources...  we need to supply
600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // non-default values for some configs so that we can retrieve resources
601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // in the app that don't have a default.  The most important of these is
602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the API version because key resources like icons will have an implicit
603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // version if they are using newer config types like density.
604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_config config;
60591447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath    memset(&config, 0, sizeof(ResTable_config));
606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[0] = 'e';
607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[1] = 'n';
608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[0] = 'U';
609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[1] = 'S';
610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.orientation = ResTable_config::ORIENTATION_PORT;
611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.density = ResTable_config::DENSITY_MEDIUM;
612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.sdkVersion = 10000; // Very high.
613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenWidthDp = 320;
614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenHeightDp = 480;
615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.smallestScreenWidthDp = 320;
616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets.setConfiguration(config);
617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ResTable& res = assets.getResources(false);
619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (&res == NULL) {
620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strcmp("resources", option) == 0) {
625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
626282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        res.print(bundle->getValues());
627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("strings", option) == 0) {
630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResStringPool* pool = res.getTableStringBlock(0);
631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printStringPool(pool);
632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmltree", option) == 0) {
634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree tree;
642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER);
643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.restart();
654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.uninit();
656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmlstrings", option) == 0) {
661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree tree;
669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER);
670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
677282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
679282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printStringPool(&tree.getStrings());
681282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
682282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
686282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ResXMLTree tree;
687282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        asset = assets.openNonAsset("AndroidManifest.xml",
688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                            Asset::ACCESS_BUFFER);
689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (asset == NULL) {
690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.setTo(asset->getBuffer(true),
695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       asset->getLength()) != NO_ERROR) {
696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        tree.restart();
700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcmp("permissions", option) == 0) {
702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 tag(tree.getElementName(&len));
715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d tag %s\n", depth, tag.string());
716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 pkg = getAttribute(tree, NULL, "package", NULL);
7222675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "permission") {
724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 name = getAttribute(tree, NAME_ATTR, &error);
726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
7302675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("permission: %s\n",
7312675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(name.string()).string());
732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "uses-permission") {
733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 name = getAttribute(tree, NAME_ATTR, &error);
735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
73958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(name,
74058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
74158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badging", option) == 0) {
745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<String8> locales;
746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getLocales(&locales);
747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            SortedVector<int> densities;
751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NC = configs.size();
752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NC; i++) {
753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int dens = configs[i].density;
754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dens == 0) {
755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    dens = 160;
756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                densities.add(dens);
758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
759282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
763282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 error;
764282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinActivity = false;
765282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isMainActivity = false;
766282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isLauncherActivity = false;
7670a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            bool isLeanbackLauncherActivity = false;
768282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isSearchable = false;
769282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinApplication = false;
770ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            bool withinSupportsInput = false;
771282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinReceiver = false;
772282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinService = false;
773282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinIntentFilter = false;
774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasMainActivity = false;
775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherActivities = false;
776282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherReceivers = false;
777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherServices = false;
778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWallpaperService = false;
779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasImeService = false;
780a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasAccessibilityService = false;
781a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasPrintService = false;
782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWidgetReceivers = false;
783a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasDeviceAdminReceiver = false;
784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasIntentFilter = false;
78594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasPaymentService = false;
786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actMainActivity = false;
787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWidgetReceivers = false;
788a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actDeviceAdminEnabled = false;
789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actImeService = false;
790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWallpaperService = false;
791a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actAccessibilityService = false;
792a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actPrintService = false;
79394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actHostApduService = false;
79494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actOffHostApduService = false;
79594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaHostPaymentCategory = false;
79694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaOffHostPaymentCategory = false;
797a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
798a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // These permissions are required by services implementing services
799a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // the system binds to (IME, Accessibility, PrintServices, etc.)
800a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindDeviceAdminPermission = false;
801a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindInputMethodPermission = false;
802a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindAccessibilityServicePermission = false;
803a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindPrintServicePermission = false;
80494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasBindNfcServicePermission = false;
805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // These two implement the implicit permissions that are granted
807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // to pre-1.6 applications.
808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteExternalStoragePermission = false;
809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadPhoneStatePermission = false;
810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If an app requests write storage, they will also get read storage.
812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadExternalStoragePermission = false;
813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Implement transition to read and write call log.
815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadContactsPermission = false;
816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteContactsPermission = false;
817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadCallLogPermission = false;
818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteCallLogPermission = false;
819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This next group of variables is used to implement a group of
821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // backward-compatibility heuristics necessitated by the addition of
822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // some new uses-feature constants in 2.1 and 2.2. In most cases, the
823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // heuristic is "if an app requests a permission but doesn't explicitly
824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // request the corresponding <uses-feature>, presume it's there anyway".
825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specCameraFeature = false; // camera-related
826282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specCameraAutofocusFeature = false;
827282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqCameraAutofocusFeature = false;
828282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqCameraFlashFeature = false;
829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasCameraPermission = false;
830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specLocationFeature = false; // location-related
831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specNetworkLocFeature = false;
832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqNetworkLocFeature = false;
833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specGpsFeature = false;
834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqGpsFeature = false;
835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasMockLocPermission = false;
836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasCoarseLocPermission = false;
837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasGpsPermission = false;
838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasGeneralLocPermission = false;
839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specBluetoothFeature = false; // Bluetooth API-related
840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasBluetoothPermission = false;
841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specMicrophoneFeature = false; // microphone-related
842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasRecordAudioPermission = false;
843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specWiFiFeature = false;
844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWiFiPermission = false;
845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specTelephonyFeature = false; // telephony-related
846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqTelephonySubFeature = false;
847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasTelephonyPermission = false;
848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specTouchscreenFeature = false; // touchscreen-related
849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specMultitouchFeature = false;
850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqDistinctMultitouchFeature = false;
851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specScreenPortraitFeature = false;
852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specScreenLandscapeFeature = false;
853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqScreenPortraitFeature = false;
854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqScreenLandscapeFeature = false;
855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // 2.2 also added some other features that apps can request, but that
856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // have no corresponding permission, so we cannot implement any
857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // back-compatibility heuristic for them. The below are thus unnecessary
858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // (but are retained here for documentary purposes.)
859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specCompassFeature = false;
860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAccelerometerFeature = false;
861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specProximityFeature = false;
862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAmbientLightFeature = false;
863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specLiveWallpaperFeature = false;
864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int targetSdk = 0;
866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int smallScreen = 1;
867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int normalScreen = 1;
868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largeScreen = 1;
869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int xlargeScreen = 1;
870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int anyDensity = 1;
871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int requiresSmallestWidthDp = 0;
872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int compatibleWidthLimitDp = 0;
873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largestWidthLimitDp = 0;
874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 pkg;
875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityName;
876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityLabel;
877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityIcon;
8780a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            String8 activityBanner;
879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 receiverName;
880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 serviceName;
881ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            Vector<String8> supportedInput;
882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (depth < 2) {
886ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if (withinSupportsInput && !supportedInput.isEmpty()) {
887ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("supports-input: '");
888ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            const size_t N = supportedInput.size();
889ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            for (size_t i=0; i<N; i++) {
8902675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                printf("%s", ResTable::normalizeForOutput(
8912675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        supportedInput[i].string()).string());
892ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (i != N - 1) {
893ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("' '");
894ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else {
895ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("'\n");
896ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
897ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
898ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            supportedInput.clear();
899ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        }
900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = false;
901ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = false;
902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 3) {
9030a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                        if (withinActivity && isMainActivity) {
9042675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            String8 aName(getComponentName(pkg, activityName));
9050a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (isLauncherActivity) {
9060a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf("launchable-activity:");
9079eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                if (aName.length() > 0) {
9089eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                    printf(" name='%s' ",
9099eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                            ResTable::normalizeForOutput(aName.string()).string());
9100a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                }
9110a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf(" label='%s' icon='%s'\n",
9129eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
9139eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityIcon.string()).string());
9140a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            }
9150a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (isLeanbackLauncherActivity) {
9160a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf("leanback-launchable-activity:");
9179eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                if (aName.length() > 0) {
9189eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                    printf(" name='%s' ",
9199eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                            ResTable::normalizeForOutput(aName.string()).string());
9200a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                }
9210a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf(" label='%s' icon='%s' banner='%s'\n",
9229eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
9239eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityIcon.string()).string(),
9249eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityBanner.string()).string());
925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
927282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (!hasIntentFilter) {
928282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherActivities |= withinActivity;
929282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherReceivers |= withinReceiver;
930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherServices |= withinService;
93194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        } else {
93294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (withinService) {
93394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
93494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        hasBindNfcServicePermission);
93594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
93694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        hasBindNfcServicePermission);
93794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
938282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinActivity = false;
940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinService = false;
941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinReceiver = false;
942282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasIntentFilter = false;
9430a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                        isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false;
944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 4) {
945282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (withinIntentFilter) {
946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (withinActivity) {
947282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasMainActivity |= actMainActivity;
948282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasOtherActivities |= !actMainActivity;
949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinReceiver) {
950282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWidgetReceivers |= actWidgetReceivers;
951a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
952a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindDeviceAdminPermission);
953a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled);
954282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinService) {
955282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasImeService |= actImeService;
956282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWallpaperService |= actWallpaperService;
957a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasAccessibilityService |= (actAccessibilityService &&
958a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindAccessibilityServicePermission);
959a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasPrintService |= (actPrintService && hasBindPrintServicePermission);
960a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasOtherServices |= (!actImeService && !actWallpaperService &&
96194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        !actAccessibilityService && !actPrintService &&
96294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        !actHostApduService && !actOffHostApduService);
963282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
964282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
965282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinIntentFilter = false;
966282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
969282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 tag(tree.getElementName(&len));
974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d,  %s\n", depth, tag.string());
975282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
976282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    pkg = getAttribute(tree, NULL, "package", NULL);
9812675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("package: name='%s' ",
9822675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(pkg.string()).string());
983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error);
984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string());
986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (versionCode > 0) {
989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='%d' ", versionCode);
990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='' ");
992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error);
994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string());
996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
9982675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("versionName='%s'\n",
9992675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(versionName.string()).string());
1000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2) {
1001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinApplication = false;
1002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag == "application") {
1003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = true;
1004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 label;
1006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t NL = locales.size();
1007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<NL; i++) {
1008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char* localeStr =  locales[i].string();
1009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setLocale(localeStr != NULL ? localeStr : "");
1010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (llabel != "") {
1012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                if (localeStr == NULL || strlen(localeStr) == 0) {
1013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    label = llabel;
10142675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    printf("application-label:'%s'\n",
10152675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                            ResTable::normalizeForOutput(llabel.string()).string());
1016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                } else {
1017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    if (label == "") {
1018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        label = llabel;
1019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    }
1020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    printf("application-label-%s:'%s'\n", localeStr,
10212675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                           ResTable::normalizeForOutput(llabel.string()).string());
1022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResTable_config tmpConfig = config;
1027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t ND = densities.size();
1028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<ND; i++) {
1029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            tmpConfig.density = densities[i];
1030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setConfiguration(tmpConfig);
1031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (icon != "") {
10332675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                printf("application-icon-%d:'%s'\n", densities[i],
10342675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(icon.string()).string());
1035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        assets.setConfiguration(config);
1038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
1042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1043282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1044282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
1045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
1047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
10492675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        printf("application: label='%s' ",
10502675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                ResTable::normalizeForOutput(label.string()).string());
10512675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        printf("icon='%s'\n", ResTable::normalizeForOutput(icon.string()).string());
1052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (testOnly != 0) {
1053282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("testOnly='%d'\n", testOnly);
1054282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0);
1057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string());
1059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1061282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (debuggable != 0) {
1062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("application-debuggable\n");
1063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1064282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-sdk") {
1065282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
1066282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1067282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
1068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
1069282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
1070282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
1071282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
1072282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1073282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1074282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut") targetSdk = 4;
10752675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("sdkVersion:'%s'\n",
10762675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1077282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
1078282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            targetSdk = code;
1079282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("sdkVersion:'%d'\n", code);
1080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1081282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1);
1082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (code != -1) {
1083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("maxSdkVersion:'%d'\n", code);
1084282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1085282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
1086282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1087282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
1088282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
1089282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
1090282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
1091282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
1092282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1093282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1094282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
10952675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("targetSdkVersion:'%s'\n",
10962675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1097282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
1098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (targetSdk < code) {
1099282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                targetSdk = code;
1100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("targetSdkVersion:'%d'\n", code);
1102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-configuration") {
1104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqTouchScreen = getIntegerAttribute(tree,
1105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_TOUCH_SCREEN_ATTR, NULL, 0);
1106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqKeyboardType = getIntegerAttribute(tree,
1107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
1108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqHardKeyboard = getIntegerAttribute(tree,
1109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_HARD_KEYBOARD_ATTR, NULL, 0);
1110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqNavigation = getIntegerAttribute(tree,
1111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_NAVIGATION_ATTR, NULL, 0);
1112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqFiveWayNav = getIntegerAttribute(tree,
1113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
1114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("uses-configuration:");
1115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqTouchScreen != 0) {
1116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqTouchScreen='%d'", reqTouchScreen);
1117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqKeyboardType != 0) {
1119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqKeyboardType='%d'", reqKeyboardType);
1120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqHardKeyboard != 0) {
1122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqHardKeyboard='%d'", reqHardKeyboard);
1123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqNavigation != 0) {
1125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqNavigation='%d'", reqNavigation);
1126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqFiveWayNav != 0) {
1128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqFiveWayNav='%d'", reqFiveWayNav);
1129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("\n");
1131ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    } else if (tag == "supports-input") {
1132ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = true;
1133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-screens") {
1134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        smallScreen = getIntegerAttribute(tree,
1135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                SMALL_SCREEN_ATTR, NULL, 1);
1136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        normalScreen = getIntegerAttribute(tree,
1137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                NORMAL_SCREEN_ATTR, NULL, 1);
1138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        largeScreen = getIntegerAttribute(tree,
1139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                LARGE_SCREEN_ATTR, NULL, 1);
1140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        xlargeScreen = getIntegerAttribute(tree,
1141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                XLARGE_SCREEN_ATTR, NULL, 1);
1142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        anyDensity = getIntegerAttribute(tree,
1143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                ANY_DENSITY_ATTR, NULL, 1);
1144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        requiresSmallestWidthDp = getIntegerAttribute(tree,
1145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0);
1146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        compatibleWidthLimitDp = getIntegerAttribute(tree,
1147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0);
1148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        largestWidthLimitDp = getIntegerAttribute(tree,
1149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0);
1150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-feature") {
1151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            int req = getIntegerAttribute(tree,
1155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    REQUIRED_ATTR, NULL, 1);
1156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "android.hardware.camera") {
1158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specCameraFeature = true;
1159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.camera.autofocus") {
1160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // these have no corresponding permission to check for,
1161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // but should imply the foundational camera permission
1162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqCameraAutofocusFeature = reqCameraAutofocusFeature || req;
1163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specCameraAutofocusFeature = true;
1164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (req && (name == "android.hardware.camera.flash")) {
1165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // these have no corresponding permission to check for,
1166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // but should imply the foundational camera permission
1167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqCameraFlashFeature = true;
1168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.location") {
1169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specLocationFeature = true;
1170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.location.network") {
1171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specNetworkLocFeature = true;
1172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqNetworkLocFeature = reqNetworkLocFeature || req;
1173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.location.gps") {
1174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specGpsFeature = true;
1175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqGpsFeature = reqGpsFeature || req;
1176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.bluetooth") {
1177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specBluetoothFeature = true;
1178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.touchscreen") {
1179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specTouchscreenFeature = true;
1180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.touchscreen.multitouch") {
1181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specMultitouchFeature = true;
1182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
1183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqDistinctMultitouchFeature = reqDistinctMultitouchFeature || req;
1184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.microphone") {
1185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specMicrophoneFeature = true;
1186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.wifi") {
1187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specWiFiFeature = true;
1188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.telephony") {
1189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specTelephonyFeature = true;
1190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (req && (name == "android.hardware.telephony.gsm" ||
1191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                               name == "android.hardware.telephony.cdma")) {
1192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // these have no corresponding permission to check for,
1193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // but should imply the foundational telephony permission
1194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqTelephonySubFeature = true;
1195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.screen.portrait") {
1196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specScreenPortraitFeature = true;
1197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.screen.landscape") {
1198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specScreenLandscapeFeature = true;
1199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("uses-feature%s:'%s'\n",
12012675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    req ? "" : "-not-required",
12022675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                            ResTable::normalizeForOutput(name.string()).string());
1203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            int vers = getIntegerAttribute(tree,
1205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    GL_ES_VERSION_ATTR, &error);
1206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error == "") {
1207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                printf("uses-gl-es:'0x%x'\n", vers);
1208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-permission") {
1211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "android.permission.CAMERA") {
1214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasCameraPermission = true;
1215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
1216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasGpsPermission = true;
1217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
1218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasMockLocPermission = true;
1219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
1220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasCoarseLocPermission = true;
1221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
1222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.INSTALL_LOCATION_PROVIDER") {
1223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasGeneralLocPermission = true;
1224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.BLUETOOTH" ||
1225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.BLUETOOTH_ADMIN") {
1226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasBluetoothPermission = true;
1227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.RECORD_AUDIO") {
1228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasRecordAudioPermission = true;
1229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
1230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CHANGE_WIFI_STATE" ||
1231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
1232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWiFiPermission = true;
1233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.CALL_PHONE" ||
1234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CALL_PRIVILEGED" ||
1235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.MODIFY_PHONE_STATE" ||
1236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.PROCESS_OUTGOING_CALLS" ||
1237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.READ_SMS" ||
1238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_SMS" ||
1239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_MMS" ||
1240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_WAP_PUSH" ||
1241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.SEND_SMS" ||
1242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.WRITE_APN_SETTINGS" ||
1243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.WRITE_SMS") {
1244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasTelephonyPermission = true;
1245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
1246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteExternalStoragePermission = true;
1247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
1248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadExternalStoragePermission = true;
1249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_PHONE_STATE") {
1250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadPhoneStatePermission = true;
1251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_CONTACTS") {
1252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadContactsPermission = true;
1253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_CONTACTS") {
1254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteContactsPermission = true;
1255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_CALL_LOG") {
1256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadCallLogPermission = true;
1257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_CALL_LOG") {
1258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteCallLogPermission = true;
1259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
126058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
126158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            printUsesPermission(name,
126258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                                    getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
126358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                                    getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
126458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                       } else {
1265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-package") {
1270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
12722675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("uses-package:'%s'\n",
12732675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "original-package") {
1280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
12822675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("original-package:'%s'\n",
12832675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-gl-texture") {
1290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
12922675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("supports-gl-texture:'%s'\n",
12932675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "compatible-screens") {
1300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printCompatibleScreens(tree);
1301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        depth--;
1302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "package-verifier") {
1303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error);
1306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (publicKey != "" && error == "") {
1307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                printf("package-verifier: name='%s' publicKey='%s'\n",
13082675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(name.string()).string(),
13092675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(publicKey.string()).string());
1310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1313ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                } else if (depth == 3) {
1314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinActivity = false;
1315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinReceiver = false;
1316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinService = false;
1317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasIntentFilter = false;
131894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasMetaHostPaymentCategory = false;
131994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasMetaOffHostPaymentCategory = false;
132094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindDeviceAdminPermission = false;
132194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindInputMethodPermission = false;
132294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindAccessibilityServicePermission = false;
132394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindPrintServicePermission = false;
132494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindNfcServicePermission = false;
1325ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    if (withinApplication) {
1326ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if(tag == "activity") {
1327ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinActivity = true;
1328ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityName = getAttribute(tree, NAME_ATTR, &error);
1329ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1330ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1331ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1332ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1333ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1335ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1336ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1337ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
1338ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1339ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1340ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1342ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1343ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1344ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
1345ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1346ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1347ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
13490a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            activityBanner = getResolvedAttribute(&res, tree, BANNER_ATTR, &error);
13500a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (error != "") {
13510a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
13520a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                        error.string());
13530a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                goto bail;
13540a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            }
13550a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn
1356ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            int32_t orien = getResolvedIntegerAttribute(&res, tree,
1357ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    SCREEN_ORIENTATION_ATTR, &error);
1358ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error == "") {
1359ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (orien == 0 || orien == 6 || orien == 8) {
1360ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests landscape, sensorLandscape, or reverseLandscape.
1361ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    reqScreenLandscapeFeature = true;
1362ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else if (orien == 1 || orien == 7 || orien == 9) {
1363ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests portrait, sensorPortrait, or reversePortrait.
1364ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    reqScreenPortraitFeature = true;
1365ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1367ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "uses-library") {
1368ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
1369ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1370ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1371ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for uses-library"
1372ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1373ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1374ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1375ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            int req = getIntegerAttribute(tree,
1376ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    REQUIRED_ATTR, NULL, 1);
1377ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("uses-library%s:'%s'\n",
13782675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    req ? "" : "-not-required", ResTable::normalizeForOutput(
13792675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                            libraryName.string()).string());
1380ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "receiver") {
1381ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinReceiver = true;
1382ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            receiverName = getAttribute(tree, NAME_ATTR, &error);
1383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1384ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1385ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1386ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for receiver:"
1387ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1388ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1389ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1390a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1391a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1392a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1393a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_DEVICE_ADMIN") {
1394a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindDeviceAdminPermission = true;
1395a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1396a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
1397a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1398a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        " receiver '%s': %s\n", receiverName.string(), error.string());
1399a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
1400ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "service") {
1401ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinService = true;
1402ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            serviceName = getAttribute(tree, NAME_ATTR, &error);
1403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1404ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1405ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1406ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "service:%s\n", error.string());
1407ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1408ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1409a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1410a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1411a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1412a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_INPUT_METHOD") {
1413a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindInputMethodPermission = true;
1414a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
1415a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindAccessibilityServicePermission = true;
1416a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
1417a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindPrintServicePermission = true;
141894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                } else if (permission == "android.permission.BIND_NFC_SERVICE") {
141994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasBindNfcServicePermission = true;
1420a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1421a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
1422a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1423a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        " service '%s': %s\n", serviceName.string(), error.string());
1424a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
1425ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
1426ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 metaDataName = getAttribute(tree, NAME_ATTR, &error);
1427ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1428ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1429ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "meta-data:%s\n", error.string());
1430ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1431ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
14322675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("meta-data: name='%s' ",
14332675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(metaDataName.string()).string());
143476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                            printResolvedResourceAttribute(&res, tree, VALUE_ATTR, String8("value"),
143576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                    &error);
1436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
143776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                // Try looking for a RESOURCE_ATTR
143876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                error = "";
143976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                printResolvedResourceAttribute(&res, tree, RESOURCE_ATTR,
144076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                        String8("resource"), &error);
1441ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (error != "") {
144276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                    fprintf(stderr, "ERROR getting 'android:value' or "
144376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                            "'android:resource' attribute for "
144476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                            "meta-data:%s\n", error.string());
1445ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    goto bail;
1446ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1447ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
144876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                            printf("\n");
1449ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (withinSupportsInput && tag == "input-type") {
1450ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 name = getAttribute(tree, NAME_ATTR, &error);
1451ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (name != "" && error == "") {
1452ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                supportedInput.add(name);
1453ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            } else {
1454ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1455ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1459a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
146094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                } else if (depth == 4) {
146194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (tag == "intent-filter") {
146294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        hasIntentFilter = true;
146394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        withinIntentFilter = true;
146494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actMainActivity = false;
146594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actWidgetReceivers = false;
146694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actImeService = false;
146794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actWallpaperService = false;
146894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actAccessibilityService = false;
146994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actPrintService = false;
147094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actDeviceAdminEnabled = false;
147194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actHostApduService = false;
147294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actOffHostApduService = false;
147394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    } else if (withinService && tag == "meta-data") {
147494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
147594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (error != "") {
147694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute for"
147794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
147894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            goto bail;
147994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        }
148094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
148194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (name == "android.nfc.cardemulation.host_apdu_service" ||
148294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                name == "android.nfc.cardemulation.off_host_apdu_service") {
148394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            bool offHost = true;
148494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (name == "android.nfc.cardemulation.host_apdu_service") {
148594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                offHost = false;
148694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
148794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
148894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            String8 xmlPath = getResolvedAttribute(&res, tree, RESOURCE_ATTR, &error);
148994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (error != "") {
149094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:resource' attribute for"
149194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
149294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                goto bail;
149394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
149494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
149594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
149694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    offHost, &error);
149794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (error != "") {
149894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                fprintf(stderr, "ERROR getting AID category for service '%s'\n",
149994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        serviceName.string());
150094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                goto bail;
150194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
150294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
150394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            const size_t catLen = categories.size();
150494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            for (size_t i = 0; i < catLen; i++) {
150594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                bool paymentCategory = (categories[i] == "payment");
150694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                if (offHost) {
150794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasMetaOffHostPaymentCategory |= paymentCategory;
150894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                } else {
150994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasMetaHostPaymentCategory |= paymentCategory;
151094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                }
151194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
151294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        }
151394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
1514a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                } else if ((depth == 5) && withinIntentFilter) {
1515a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    String8 action;
1516a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "action") {
1517a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        action = getAttribute(tree, NAME_ATTR, &error);
1518a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1519a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1520a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1521a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1522a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1523a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1524a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1525a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.intent.action.MAIN") {
1526a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isMainActivity = true;
1527a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actMainActivity = true;
1528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1529a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinReceiver) {
1530a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
1531a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWidgetReceivers = true;
1532a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
1533a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actDeviceAdminEnabled = true;
1534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1535a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinService) {
1536a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.view.InputMethod") {
1537a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actImeService = true;
1538a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.service.wallpaper.WallpaperService") {
1539a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWallpaperService = true;
1540a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.accessibilityservice.AccessibilityService") {
1541a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actAccessibilityService = true;
1542a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.printservice.PrintService") {
1543a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actPrintService = true;
154494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            } else if (action == "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
154594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                actHostApduService = true;
154694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            } else if (action == "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
154794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                actOffHostApduService = true;
1548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1550a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (action == "android.intent.action.SEARCH") {
1551a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            isSearchable = true;
1552a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1553a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
1554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1555a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "category") {
1556a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        String8 category = getAttribute(tree, NAME_ATTR, &error);
1557a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1558a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'name' attribute: %s\n",
1559a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1560a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1561a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1562a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1563a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (category == "android.intent.category.LAUNCHER") {
1564a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isLauncherActivity = true;
15650a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            } else if (category == "android.intent.category.LEANBACK_LAUNCHER") {
15660a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                isLeanbackLauncherActivity = true;
1567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-1.6 implicitly granted permission compatibility logic
1574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 4) {
1575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteExternalStoragePermission) {
157658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
157758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
157858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 4"));
1579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasWriteExternalStoragePermission = true;
1580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadPhoneStatePermission) {
158258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.READ_PHONE_STATE"));
158358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"),
158458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 4"));
1585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If the application has requested WRITE_EXTERNAL_STORAGE, we will
1589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // force them to always take READ_EXTERNAL_STORAGE as well.  We always
1590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // do this (regardless of target API version) because we can't have
1591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // an app with write permission but not read permission.
1592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
159358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"));
159458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
159558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                        String8("requested WRITE_EXTERNAL_STORAGE"));
1596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-JellyBean call log permission compatibility.
1599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 16) {
1600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadCallLogPermission && hasReadContactsPermission) {
160158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.READ_CALL_LOG"));
160258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
160358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 16 and requested READ_CONTACTS"));
1604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
160658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.WRITE_CALL_LOG"));
160758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"),
160858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 16 and requested WRITE_CONTACTS"));
1609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            /* The following blocks handle printing "inferred" uses-features, based
1613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * on whether related features or permissions are used by the app.
1614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * Note that the various spec*Feature variables denote whether the
1615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * relevant tag was *present* in the AndroidManfest, not that it was
1616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * present and set to true.
1617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             */
1618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Camera-related back-compatibility logic
1619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specCameraFeature) {
1620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (reqCameraFlashFeature) {
1621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // if app requested a sub-feature (autofocus or flash) and didn't
1622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // request the base camera feature, we infer that it meant to
1623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-feature:'android.hardware.camera'\n");
1624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-feature:'android.hardware.camera'," \
1625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'requested android.hardware.camera.flash feature'\n");
1626282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (reqCameraAutofocusFeature) {
1627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // if app requested a sub-feature (autofocus or flash) and didn't
1628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // request the base camera feature, we infer that it meant to
1629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-feature:'android.hardware.camera'\n");
1630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-feature:'android.hardware.camera'," \
1631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'requested android.hardware.camera.autofocus feature'\n");
1632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (hasCameraPermission) {
16332675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    // if app wants to use camera but didn't request the feature, we infer
1634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // that it meant to, and further that it wants autofocus
1635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // (which was the 1.0 - 1.5 behavior)
1636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-feature:'android.hardware.camera'\n");
1637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (!specCameraAutofocusFeature) {
1638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("uses-feature:'android.hardware.camera.autofocus'\n");
1639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("uses-implied-feature:'android.hardware.camera.autofocus'," \
1640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                "'requested android.permission.CAMERA permission'\n");
1641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Location-related back-compatibility logic
1646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specLocationFeature &&
1647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (hasMockLocPermission || hasCoarseLocPermission || hasGpsPermission ||
1648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                 hasGeneralLocPermission || reqNetworkLocFeature || reqGpsFeature)) {
1649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app either takes a location-related permission or requests one of the
1650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // sub-features, we infer that it also meant to request the base location feature
1651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.location'\n");
1652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.location'," \
1653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested a location access permission'\n");
1654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specGpsFeature && hasGpsPermission) {
1656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes GPS (FINE location) perm but does not request the GPS
1657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // feature, we infer that it meant to
1658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.location.gps'\n");
1659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.location.gps'," \
1660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.permission.ACCESS_FINE_LOCATION permission'\n");
1661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specNetworkLocFeature && hasCoarseLocPermission) {
1663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes Network location (COARSE location) perm but does not request the
1664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // network location feature, we infer that it meant to
1665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.location.network'\n");
1666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.location.network'," \
1667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.permission.ACCESS_COARSE_LOCATION permission'\n");
1668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Bluetooth-related compatibility logic
1671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specBluetoothFeature && hasBluetoothPermission && (targetSdk > 4)) {
1672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes a Bluetooth permission but does not request the Bluetooth
1673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // feature, we infer that it meant to
1674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.bluetooth'\n");
1675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.bluetooth'," \
1676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.permission.BLUETOOTH or android.permission.BLUETOOTH_ADMIN " \
1677282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "permission and targetSdkVersion > 4'\n");
1678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1679282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Microphone-related compatibility logic
1681282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specMicrophoneFeature && hasRecordAudioPermission) {
1682282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes the record-audio permission but does not request the microphone
1683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // feature, we infer that it meant to
1684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.microphone'\n");
1685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.microphone'," \
1686282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.permission.RECORD_AUDIO permission'\n");
1687282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // WiFi-related compatibility logic
1690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specWiFiFeature && hasWiFiPermission) {
1691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes one of the WiFi permissions but does not request the WiFi
1692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // feature, we infer that it meant to
1693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.wifi'\n");
1694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.wifi'," \
1695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.permission.ACCESS_WIFI_STATE, " \
1696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "android.permission.CHANGE_WIFI_STATE, or " \
1697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "android.permission.CHANGE_WIFI_MULTICAST_STATE permission'\n");
1698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Telephony-related compatibility logic
1701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specTelephonyFeature && (hasTelephonyPermission || reqTelephonySubFeature)) {
1702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes one of the telephony permissions or requests a sub-feature but
1703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // does not request the base telephony feature, we infer that it meant to
1704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.telephony'\n");
1705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.telephony'," \
1706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested a telephony-related permission or feature'\n");
1707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Touchscreen-related back-compatibility logic
1710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specTouchscreenFeature) { // not a typo!
1711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // all apps are presumed to require a touchscreen, unless they explicitly say
1712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
1713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Note that specTouchscreenFeature is true if the tag is present, regardless
1714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // of whether its value is true or false, so this is safe
1715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.touchscreen'\n");
1716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.touchscreen'," \
1717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'assumed you require a touch screen unless explicitly made optional'\n");
1718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specMultitouchFeature && reqDistinctMultitouchFeature) {
1720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes one of the telephony permissions or requests a sub-feature but
1721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // does not request the base telephony feature, we infer that it meant to
1722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.touchscreen.multitouch'\n");
1723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.touchscreen.multitouch'," \
1724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.hardware.touchscreen.multitouch.distinct feature'\n");
1725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Landscape/portrait-related compatibility logic
1728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specScreenLandscapeFeature && !specScreenPortraitFeature) {
1729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // If the app has specified any activities in its manifest
1730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // that request a specific orientation, then assume that
1731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // orientation is required.
1732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (reqScreenLandscapeFeature) {
1733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-feature:'android.hardware.screen.landscape'\n");
1734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-feature:'android.hardware.screen.landscape'," \
1735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'one or more activities have specified a landscape orientation'\n");
1736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (reqScreenPortraitFeature) {
1738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-feature:'android.hardware.screen.portrait'\n");
1739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-feature:'android.hardware.screen.portrait'," \
1740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'one or more activities have specified a portrait orientation'\n");
1741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasMainActivity) {
1745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("main\n");
1746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWidgetReceivers) {
1748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("app-widget\n");
1749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1750a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasDeviceAdminReceiver) {
1751a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                printf("device-admin\n");
1752a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
1753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasImeService) {
1754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("ime\n");
1755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWallpaperService) {
1757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("wallpaper\n");
1758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1759a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasAccessibilityService) {
1760a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                printf("accessibility\n");
1761a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
1762a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasPrintService) {
1763a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                printf("print\n");
1764a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
176594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (hasPaymentService) {
176694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                printf("payment\n");
176794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
1768282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherActivities) {
1769282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-activities\n");
1770282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1771282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (isSearchable) {
1772282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("search\n");
1773282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherReceivers) {
1775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-receivers\n");
1776282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherServices) {
1778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-services\n");
1779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1780282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // For modern apps, if screen size buckets haven't been specified
1782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // but the new width ranges have, then infer the buckets from them.
1783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
1784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    && requiresSmallestWidthDp > 0) {
1785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int compatWidth = compatibleWidthLimitDp;
1786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (compatWidth <= 0) {
1787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    compatWidth = requiresSmallestWidthDp;
1788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
1790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = -1;
1791282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = 0;
1793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
1795282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = -1;
1796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = 0;
1798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
1800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = -1;
1801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = 0;
1803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1804282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
1805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = -1;
1806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = 0;
1808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Determine default values for any unspecified screen sizes,
1812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // based on the target SDK of the package.  As of 4 (donut)
1813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // the screen size support was introduced, so all default to
1814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // enabled.
1815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0) {
1816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                smallScreen = targetSdk >= 4 ? -1 : 0;
1817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen > 0) {
1819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                normalScreen = -1;
1820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen > 0) {
1822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                largeScreen = targetSdk >= 4 ? -1 : 0;
1823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen > 0) {
1825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Introduced in Gingerbread.
1826282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                xlargeScreen = targetSdk >= 9 ? -1 : 0;
1827282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1828282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (anyDensity > 0) {
1829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
1830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        || compatibleWidthLimitDp > 0) ? -1 : 0;
1831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-screens:");
1833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen != 0) {
1834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'small'");
1835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen != 0) {
1837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'normal'");
1838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen != 0) {
1840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'large'");
1841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen != 0) {
1843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'xlarge'");
1844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
1846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
1847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (requiresSmallestWidthDp > 0) {
1848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
1849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (compatibleWidthLimitDp > 0) {
1851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
1852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largestWidthLimitDp > 0) {
1854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
1855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("locales:");
1858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NL = locales.size();
1859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NL; i++) {
1860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const char* localeStr =  locales[i].string();
1861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (localeStr == NULL || strlen(localeStr) == 0) {
1862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    localeStr = "--_--";
1863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'", localeStr);
1865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
1867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("densities:");
1869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t ND = densities.size();
1870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<ND; i++) {
1871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%d'", densities[i]);
1872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
1874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
1876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (dir != NULL) {
1877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dir->getFileCount() > 0) {
1878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("native-code:");
1879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    for (size_t i=0; i<dir->getFileCount(); i++) {
18802675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        printf(" '%s'", ResTable::normalizeForOutput(
18812675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                dir->getFileName(i).string()).string());
1882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("\n");
1884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                delete dir;
1886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badger", option) == 0) {
1888282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s", CONSOLE_DATA);
1889282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("configurations", option) == 0) {
1890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
1891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
1892282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = configs.size();
1893282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<N; i++) {
1894282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("%s\n", configs[i].toString().string());
1895282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1896282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
1897282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
1898282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1899282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1901282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
1903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1904282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
1905282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (asset) {
1906282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete asset;
1907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
1909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1911282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "add" command, which wants to add files to a new or
1914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * pre-existing archive.
1915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doAdd(Bundle* bundle)
1917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
1919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
1920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
1921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getUpdate()) {
1923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* avoid confusion */
1924282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: can't use '-u' with add\n");
1925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1927282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1928282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
1929282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
1930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1931282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1932282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
1933282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1934282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
1935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
1936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1937282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1938282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, true);
1940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
1941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
1942282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1943282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1945282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
1946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
1947282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1948282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
1949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s'... (from gzip)\n", fileName);
1950282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
1951282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
1952282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (bundle->getJunkPath()) {
1953282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 storageName = String8(fileName).getPathLeaf();
19542675f769673f69b0661ddee346292f25cb30a296Maurice Chu                printf(" '%s' as '%s'...\n", fileName,
19552675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        ResTable::normalizeForOutput(storageName.string()).string());
1956282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, storageName.string(),
1957282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  bundle->getCompressionMethod(), NULL);
1958282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
1959282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'...\n", fileName);
1960282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
1961282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1962282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1963282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
1964282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
1965282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (result == NAME_NOT_FOUND) {
1966282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": file not found\n");
1967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (result == ALREADY_EXISTS) {
1968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": already exists in archive\n");
1969282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
1970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "\n");
1971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1975282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1976282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
1977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
1979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
1980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
1981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Delete files from an existing archive.
1986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doRemove(Bundle* bundle)
1988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
1990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
1991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
1992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
1994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
1995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
1998282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1999282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
2000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
2001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, false);
2005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
2006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
2007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zipFileName);
2008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
2013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ZipEntry* entry;
2014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByName(fileName);
2016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (entry == NULL) {
2017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s' NOT FOUND\n", fileName);
2018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
2019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = zip->remove(entry);
2022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
2024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to delete '%s' from '%s'\n",
2025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                bundle->getFileSpecEntry(i), zipFileName);
2026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* update the archive */
2031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip->flush();
2032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
2035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
20383921e87e6e67a063caa1987937d7944b24aef489Adam Lesinskistatic status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
2039fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    const size_t numDirs = dir->getDirs().size();
2040fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    for (size_t i = 0; i < numDirs; i++) {
20413921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        bool ignore = ignoreConfig;
20423921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
20433921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        const char* dirStr = subDir->getLeaf().string();
20443921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
20453921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            ignore = true;
20463921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        }
20473921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        status_t err = addResourcesToBuilder(subDir, builder, ignore);
2048fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        if (err != NO_ERROR) {
2049fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            return err;
2050fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2051fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2052fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2053fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    const size_t numFiles = dir->getFiles().size();
2054fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    for (size_t i = 0; i < numFiles; i++) {
2055fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        sp<AaptGroup> gp = dir->getFiles().valueAt(i);
2056fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numConfigs = gp->getFiles().size();
2057fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t j = 0; j < numConfigs; j++) {
20583921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            status_t err = NO_ERROR;
20593921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            if (ignoreConfig) {
20603921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski                err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
20613921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            } else {
20623921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski                err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
20633921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            }
2064fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2065fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "Failed to add %s (%s) to builder.\n",
2066fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                        gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
2067fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                return err;
2068fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2069fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2070fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2071fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    return NO_ERROR;
2072fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski}
2073fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2074fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinskistatic String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
2075fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (split->isBase()) {
2076fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        return original;
2077fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2078fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2079fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    String8 ext(original.getPathExtension());
2080fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (ext == String8(".apk")) {
2081fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        return String8::format("%s_%s%s",
2082fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                original.getBasePath().string(),
2083fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                split->getDirectorySafeName().string(),
2084fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                ext.string());
2085fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2086fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2087fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    return String8::format("%s_%s", original.string(),
2088fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            split->getDirectorySafeName().string());
2089fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski}
2090282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2091282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2092282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Package up an asset directory and associated application files.
2093282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2094282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doPackage(Bundle* bundle)
2095282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* outputAPKFile;
2097282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int retVal = 1;
2098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err;
2099282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<AaptAssets> assets;
2100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int N;
2101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    FILE* fp;
2102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 dependencyFile;
2103fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    sp<ApkBuilder> builder;
2104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2105a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin    // -c en_XA or/and ar_XB means do pseudolocalization
2106fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
2107fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    err = configFilter->parse(bundle->getConfigurations());
2108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
2109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2111fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (configFilter->containsPseudo()) {
2112a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
2113a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin    }
2114fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (configFilter->containsPseudoBidi()) {
2115a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
2116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    N = bundle->getFileSpecCount();
2119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
212009384303dea4f3f01d5682918d7bab9bf83a02b1Adam Lesinski            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
2121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no input files\n");
2122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    outputAPKFile = bundle->getOutputAPKFile();
2126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make sure the filenames provided exist and are of the appropriate type.
2128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
2129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        FileType type;
2130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        type = getFileType(outputAPKFile);
2131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
2132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr,
2133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                "ERROR: output file '%s' exists but is not regular file\n",
2134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                outputAPKFile);
2135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Load the assets.
2140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets = new AaptAssets();
2141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Set up the resource gathering in assets if we're going to generate
2143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // dependency files. Every time we encounter a resource while slurping
2144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the tree, we'll add it to these stores so we have full resource paths
2145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // to write to a dependency file.
2146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> resPathStore = new FilePathStore;
2148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullResPaths(resPathStore);
2149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> assetPathStore = new FilePathStore;
2150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullAssetPaths(assetPathStore);
2151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = assets->slurpFromArgs(bundle);
2154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
2155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
2159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->print(String8());
2160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2162fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // Create the ApkBuilder, which will collect the compiled files
2163fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // to write to the final APK (or sets of APKs if we are building
2164fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // a Split APK.
2165fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    builder = new ApkBuilder(configFilter);
2166fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2167fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // If we are generating a Split APK, find out which configurations to split on.
2168fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (bundle->getSplitConfigurations().size() > 0) {
2169fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
2170fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numSplits = splitStrs.size();
2171fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t i = 0; i < numSplits; i++) {
2172fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            std::set<ConfigDescription> configs;
2173fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
2174fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
2175fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2176fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2177fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2178fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            err = builder->createSplitForConfigs(configs);
2179fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2180fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2181fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2182fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2183fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2184fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If they asked for any fileAs that need to be compiled, do so.
2186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
2187fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        err = buildResources(bundle, assets, builder);
2188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != 0) {
2189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // At this point we've read everything and processed everything.  From here
2194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // on out it's just writing output files.
2195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Update symbols with information about which ones are needed as Java symbols.
2200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets->applyJavaSymbols();
2201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, do that here
2206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If this is the packaging step, generate the dependency file next to
2208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the output apk (e.g. bin/resources.ap_.d)
2209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outputAPKFile) {
2210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(outputAPKFile);
2211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Add the .d extension to the dependency file.
2212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.append(".d");
2213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Else if this is the R.java dependency generation step,
2215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // generate the dependency file in the R.java package subdirectory
2216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java.d
2217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(bundle->getRClassDir());
2218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.appendPath("R.java.d");
2219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Make sure we have a clean dependency file to start with
2221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "w");
2222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
2223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out R.java constants
2226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets->havePrivateSymbols()) {
2227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getCustomPackage() == NULL) {
2228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Write the R.java file into the appropriate class directory
2229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java
2230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = writeResourceSymbols(bundle, assets, assets->getPackage(), true);
2231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const String8 customPkg(bundle->getCustomPackage());
2233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = writeResourceSymbols(bundle, assets, customPkg, true);
2234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If we have library files, we're going to write our R.java file into
2239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the appropriate class directory for those libraries as well.
2240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // e.g. gen/com/foo/app/lib/R.java
2241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getExtraPackages() != NULL) {
2242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Split on colon
2243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 libs(bundle->getExtraPackages());
2244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
2245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while (packageString != NULL) {
2246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Write the R.java file out with the correct package name
2247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                err = writeResourceSymbols(bundle, assets, String8(packageString), true);
2248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (err < 0) {
2249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    goto bail;
2250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                packageString = strtok(NULL, ":");
2252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            libs.unlockBuffer();
2254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
2256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getPackage(), false);
2257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true);
2261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out the ProGuard file
2267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = writeProguardFile(bundle, assets);
2268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
2269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write the apk
2273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
2274fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        // Gather all resources and add them to the APK Builder. The builder will then
2275fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        // figure out which Split they belong in.
2276fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        err = addResourcesToBuilder(assets, builder);
2277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
2278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2280fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2281fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const Vector<sp<ApkSplit> >& splits = builder->getSplits();
2282fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numSplits = splits.size();
2283fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t i = 0; i < numSplits; i++) {
2284fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            const sp<ApkSplit>& split = splits[i];
2285fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            String8 outputPath = buildApkName(String8(outputAPKFile), split);
2286fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            err = writeAPK(bundle, outputPath, split);
2287fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2288fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
2289fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2290fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2291fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, we need to finish up here.
2295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the writeResourceSymbols and writeAPK functions have already written the target
2296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // half of the dependency file, now we need to write the prerequisites. (files that
2297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the R.java file or .ap_ file depend on)
2298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Now that writeResourceSymbols or writeAPK has taken care of writing
2300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the targets to our dependency file, we'll write the prereqs
2301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "a+");
2302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, " : ");
2303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool includeRaw = (outputAPKFile != NULL);
2304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
2305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Also manually add the AndroidManifeset since it's not under res/ or assets/
2306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // and therefore was not added to our pathstores during slurping
2307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
2308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
2309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    retVal = 0;
2312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        SourcePos::printErrors(stderr);
2315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return retVal;
2317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching
2321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * PRECONDITIONS
2322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -S flag points to a source directory containing drawable* folders
2323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -C flag points to destination directory. The folder structure in the
2324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *     source directory will be mirrored to the destination (cache) directory
2325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
2326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * POSTCONDITIONS
2327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  Destination directory will be updated to match the PNG files in
23282675f769673f69b0661ddee346292f25cb30a296Maurice Chu *  the source directory.
2329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doCrunch(Bundle* bundle)
2331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching PNG Files in ");
2333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
2334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
2335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    updatePreProcessedCache(bundle);
2337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching on a single flag
2343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -i points to a single png file
2344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -o points to a single png output file
2345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doSingleCrunch(Bundle* bundle)
2347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
2349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
2350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 input(bundle->getSingleCrunchInputFile());
2352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 output(bundle->getSingleCrunchOutputFile());
2353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
2355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // we can't return the status_t as it gets truncate to the lower 8 bits.
2356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 42;
2357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskichar CONSOLE_DATA[2925] = {
2363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
2368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
2369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
2372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
2373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
2376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
2379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
2380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
2383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
2384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
2387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
2390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
2391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
2394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
2397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
2398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
2401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
2402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
2405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
2408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
2409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
2411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
2412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
2414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
2415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
2416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
2419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
2420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
2421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
2423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
2424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
2425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
2426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
2429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
2430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
2431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
2432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
2433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
2434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
2435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
2437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
2439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
2441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
2442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
2444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
2445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
2446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
2449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
2451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
2452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
2455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
2456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
2462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
2463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
2467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
2470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
2473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
2474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
2480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
2481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
2484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
2485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
2488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
2489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
2490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
2491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
2492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
2495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
2496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
2497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
2498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
2499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
2506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
2509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
2510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
2513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
2514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
2516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
2517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
2520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
2521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10
2526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  };
2527