Command.cpp revision e47fd129057b19862e94b89f9ba413b5ceaca498
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 "Bundle.h"
82c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include "Images.h"
92c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include "Main.h"
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceFilter.h"
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceTable.h"
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "XMLNode.h"
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
142c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/Errors.h>
152c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/KeyedVector.h>
162c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/List.h>
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/Log.h>
182c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/SortedVector.h>
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/threads.h>
202c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/Vector.h>
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <errno.h>
232c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <fcntl.h>
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiusing namespace android;
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Show version info.  All the cool kids do it.
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doVersion(Bundle* bundle)
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 0) {
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("(ignoring extra arguments)\n");
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("Android Asset Packaging Tool, v0.2\n");
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 0;
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read only.  The call fails if the file doesn't exist.
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadOnly(const char* fileName)
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip;
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, ZipFile::kOpenReadOnly);
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result == NAME_NOT_FOUND) {
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' not found\n", fileName);
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (result == PERMISSION_DENIED) {
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fileName);
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read-write.  The file will be created if it doesn't
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * already exist and "okayToCreate" is set.
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadWrite(const char* fileName, bool okayToCreate)
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int flags;
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    flags = ZipFile::kOpenReadWrite;
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (okayToCreate) {
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        flags |= ZipFile::kOpenCreate;
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, flags);
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        zip = NULL;
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return a short string describing the compression method.
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiconst char* compressionName(int method)
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (method == ZipEntry::kCompressStored) {
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Stored";
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (method == ZipEntry::kCompressDeflated) {
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Deflated";
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Unknown";
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return the percent reduction in size (0% == no compression).
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint calcPercent(long uncompressedLen, long compressedLen)
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!uncompressedLen) {
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 0;
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "list" command, which can be a simple file dump or
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * a verbose listing.
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The verbose listing closely matches the output of the Info-ZIP "unzip"
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * command.
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doList(Bundle* bundle)
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int result = 1;
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ZipEntry* entry;
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    long totalUncLen, totalCompLen;
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 1) {
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: specify zip file name (only)\n");
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadOnly(zipFileName);
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int count, i;
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("Archive:  %s\n", zipFileName);
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            " Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name\n");
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            "--------  ------  ------- -----  -------      ----  ----  ------    ----\n");
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    totalUncLen = totalCompLen = 0;
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    count = zip->getNumEntries();
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i = 0; i < count; i++) {
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByIndex(i);
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getVerbose()) {
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char dateBuf[32];
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            time_t when;
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            when = entry->getModWhen();
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                localtime(&when));
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%8ld  %-7.7s %7ld %3d%%  %8zd  %s  %08lx  %s\n",
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getUncompressedLen(),
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                compressionName(entry->getCompressionMethod()),
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getCompressedLen(),
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                calcPercent(entry->getUncompressedLen(),
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            entry->getCompressedLen()),
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (size_t) entry->getLFHOffset(),
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                dateBuf,
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getCRC32(),
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getFileName());
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s\n", entry->getFileName());
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalUncLen += entry->getUncompressedLen();
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalCompLen += entry->getCompressedLen();
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "--------          -------  ---                            -------\n");
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("%8ld          %7ld  %2d%%                            %d files\n",
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalUncLen,
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalCompLen,
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            calcPercent(totalUncLen, totalCompLen),
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zip->getNumEntries());
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getAndroidList()) {
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        AssetManager assets;
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!assets.addAssetPath(String8(zipFileName), NULL)) {
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResTable& res = assets.getResources(false);
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (&res == NULL) {
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo resource table found.\n");
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nResource table:\n");
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.print(false);
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                   Asset::ACCESS_BUFFER);
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (manifestAsset == NULL) {
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo AndroidManifest.xml found.\n");
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nAndroid manifest:\n");
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree tree;
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.setTo(manifestAsset->getBuffer(true),
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       manifestAsset->getLength());
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete manifestAsset;
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = 0;
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes)
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t N = tree.getAttributeCount();
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.getAttributeNameResID(i) == attrRes) {
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return (ssize_t)i;
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return -1;
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiString8 getAttribute(const ResXMLTree& tree, const char* ns,
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char* attr, String8* outError)
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = tree.indexOfAttribute(ns, attr);
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError)
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes,
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String8* outError, int32_t defValue = -1)
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return defValue;
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType < Res_value::TYPE_FIRST_INT
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || value.dataType > Res_value::TYPE_LAST_INT) {
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not an integer value";
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return defValue;
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return value.data;
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree,
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t attrRes, String8* outError, int32_t defValue = -1)
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return defValue;
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType == Res_value::TYPE_REFERENCE) {
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            resTable->resolveReference(&value, 0);
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType < Res_value::TYPE_FIRST_INT
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || value.dataType > Res_value::TYPE_LAST_INT) {
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not an integer value";
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return defValue;
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return value.data;
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree,
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t attrRes, String8* outError)
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType == Res_value::TYPE_STRING) {
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const uint16_t* str = tree.getAttributeStringValue(idx, &len);
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return str ? String8(str, len) : String8();
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        resTable->resolveReference(&value, 0);
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const Res_value* value2 = &value;
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len);
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic void getResolvedResourceAttribute(Res_value* value, const ResTable* resTable,
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResXMLTree& tree, uint32_t attrRes, String8* outError)
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outError != NULL) {
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            *outError = "attribute could not be found";
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, value) != NO_ERROR) {
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value->dataType == Res_value::TYPE_REFERENCE) {
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            resTable->resolveReference(value, 0);
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // The attribute was found and was resolved if need be.
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outError != NULL) {
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *outError = "error getting resolved resource attribute";
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
38576327314d2238e105f8b94909f9c0cf85caca318Maurice Chustatic void printResolvedResourceAttribute(const ResTable* resTable, const ResXMLTree& tree,
38676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        uint32_t attrRes, String8 attrLabel, String8* outError)
38776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu{
38876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    Res_value value;
38976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    getResolvedResourceAttribute(&value, resTable, tree, attrRes, outError);
39076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (*outError != "") {
39176327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        *outError = "error print resolved resource attribute";
39276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        return;
39376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
39476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (value.dataType == Res_value::TYPE_STRING) {
39576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        String8 result = getResolvedAttribute(resTable, tree, attrRes, outError);
3962675f769673f69b0661ddee346292f25cb30a296Maurice Chu        printf("%s='%s'", attrLabel.string(),
3972675f769673f69b0661ddee346292f25cb30a296Maurice Chu                ResTable::normalizeForOutput(result.string()).string());
39876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
39976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu            value.dataType <= Res_value::TYPE_LAST_INT) {
40076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='%d'", attrLabel.string(), value.data);
40176327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else {
40276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='0x%x'", attrLabel.string(), (int)value.data);
40376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
40476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu}
40576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu
406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// These are attribute resource constants for the platform, as found
407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// in android.R.attr
408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskienum {
409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LABEL_ATTR = 0x01010001,
410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ICON_ATTR = 0x01010002,
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NAME_ATTR = 0x01010003,
412a5018c900f126ee8424c82497f32983873db741bAdam Lesinski    PERMISSION_ATTR = 0x01010006,
4139d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    EXPORTED_ATTR = 0x01010010,
4149d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
41594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    RESOURCE_ATTR = 0x01010025,
416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    DEBUGGABLE_ATTR = 0x0101000f,
417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VALUE_ATTR = 0x01010024,
418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_CODE_ATTR = 0x0101021b,
419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_NAME_ATTR = 0x0101021c,
420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_ORIENTATION_ATTR = 0x0101001e,
421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MIN_SDK_VERSION_ATTR = 0x0101020c,
422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MAX_SDK_VERSION_ATTR = 0x01010271,
423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_TOUCH_SCREEN_ATTR = 0x01010227,
424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_HARD_KEYBOARD_ATTR = 0x01010229,
426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_NAVIGATION_ATTR = 0x0101022a,
427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TARGET_SDK_VERSION_ATTR = 0x01010270,
429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TEST_ONLY_ATTR = 0x01010272,
430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ANY_DENSITY_ATTR = 0x0101026c,
431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    GL_ES_VERSION_ATTR = 0x01010281,
432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SMALL_SCREEN_ATTR = 0x01010284,
433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NORMAL_SCREEN_ATTR = 0x01010285,
434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGE_SCREEN_ATTR = 0x01010286,
435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    XLARGE_SCREEN_ATTR = 0x010102bf,
436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRED_ATTR = 0x0101028e,
437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_SIZE_ATTR = 0x010102ca,
438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_DENSITY_ATTR = 0x010102cb,
439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    PUBLIC_KEY_ATTR = 0x010103a6,
44394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    CATEGORY_ATTR = 0x010103e8,
4440a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn    BANNER_ATTR = 0x10103f2,
445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4472675f769673f69b0661ddee346292f25cb30a296Maurice ChuString8 getComponentName(String8 &pkgName, String8 &componentName) {
448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = componentName.find(".");
449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 retStr(pkgName);
450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx == 0) {
451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (idx < 0) {
453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += ".";
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
4562675f769673f69b0661ddee346292f25cb30a296Maurice Chu        return componentName;
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4582675f769673f69b0661ddee346292f25cb30a296Maurice Chu    return retStr;
459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4619cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinskistatic void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResXMLTree::event_code_t code;
464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int depth = 0;
465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool first = true;
466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("compatible-screens:");
467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code == ResXMLTree::END_TAG) {
469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            depth--;
470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (depth < 0) {
471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code != ResXMLTree::START_TAG) {
476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        depth++;
4799cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        const char16_t* ctag16 = tree.getElementName(&len);
4809cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        if (ctag16 == NULL) {
4819cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            *outError = "failed to get XML element name (bad string pool)";
4829cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            return;
4839cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        }
4849cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        String8 tag(ctag16);
485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tag == "screen") {
486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int32_t screenSize = getIntegerAttribute(tree,
487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SCREEN_SIZE_ATTR, NULL, -1);
488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int32_t screenDensity = getIntegerAttribute(tree,
489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SCREEN_DENSITY_ATTR, NULL, -1);
490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (screenSize > 0 && screenDensity > 0) {
491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!first) {
492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf(",");
493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                first = false;
495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("'%d/%d'", screenSize, screenDensity);
496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("\n");
500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
50258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
50358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
50458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (maxSdkVersion != -1) {
50558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski         printf(" maxSdkVersion='%d'", maxSdkVersion);
50658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
50758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("\n");
50858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
50958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (optional) {
51058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("optional-permission: name='%s'",
51158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                ResTable::normalizeForOutput(name.string()).string());
51258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        if (maxSdkVersion != -1) {
51358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            printf(" maxSdkVersion='%d'", maxSdkVersion);
51458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        }
51558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("\n");
51658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
51758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
51858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
51958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesImpliedPermission(const String8& name, const String8& reason) {
52058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-implied-permission: name='%s' reason='%s'\n",
52158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(name.string()).string(),
52258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(reason.string()).string());
52358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
52458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
52594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam LesinskiVector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost,
52694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        String8 *outError = NULL)
52794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski{
52894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
52994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    if (aidAsset == NULL) {
53094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (outError != NULL) *outError = "xml resource does not exist";
53194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        return Vector<String8>();
53294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
53394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
53494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
53594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
53694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    bool withinApduService = false;
53794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Vector<String8> categories;
53894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
53994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    String8 error;
54094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree tree;
54194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
54294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
54394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    size_t len;
54494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    int depth = 0;
54594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree::event_code_t code;
54694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
54794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (code == ResXMLTree::END_TAG) {
54894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth--;
5499cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
5509cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
5519cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
5529cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
5539cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
5549cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
55594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
55694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 0 && tag == serviceTagName) {
55794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                withinApduService = false;
55894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
55994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
56094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        } else if (code == ResXMLTree::START_TAG) {
56194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth++;
5629cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
5639cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
5649cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
5659cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
5669cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
5679cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
56894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
56994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 1) {
57094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == serviceTagName) {
57194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    withinApduService = true;
57294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
57394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            } else if (depth == 2 && withinApduService) {
57494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == "aid-group") {
57594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    String8 category = getAttribute(tree, CATEGORY_ATTR, &error);
57694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (error != "") {
57794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (outError != NULL) *outError = error;
57894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        return Vector<String8>();
57994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
58094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
58194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    categories.add(category);
58294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
58394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
58494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        }
58594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
58694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    aidAsset->close();
58794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    return categories;
58894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski}
58994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
5909d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinskistatic void printComponentPresence(const char* componentName) {
5919d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    printf("provides-component:'%s'\n", componentName);
5929d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski}
5939d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
5942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
5952c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a feature that has been automatically added due to
5962c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * a pre-requisite or some other reason.
5972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
5982c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct ImpliedFeature {
5992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6002c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Name of the implied feature.
6012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name;
6032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6042c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * List of human-readable reasons for why this feature was implied.
6062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    SortedVector<String8> reasons;
6082c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
6092c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
6112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a <feature-group> tag in the AndroidManifest.xml
6122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
6132c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct FeatureGroup {
614d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    FeatureGroup() : openGLESVersion(-1) {}
615d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
6162c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6172c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Human readable label
6182c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6192c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 label;
6202c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6222c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Explicit features defined in the group
6232c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6242c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    KeyedVector<String8, bool> features;
625d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
626d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    /**
627d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     * OpenGL ES version required
628d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     */
629d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    int openGLESVersion;
6302c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
6312c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6322c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
6332c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const char* name, const char* reason) {
6342c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name8(name);
6352c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    ssize_t idx = impliedFeatures->indexOfKey(name8);
6362c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (idx < 0) {
6372c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        idx = impliedFeatures->add(name8, ImpliedFeature());
6382c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        impliedFeatures->editValueAt(idx).name = name8;
6392c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6402c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    impliedFeatures->editValueAt(idx).reasons.add(String8(reason));
6412c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
6422c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6432c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void printFeatureGroup(const FeatureGroup& grp,
6442c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const KeyedVector<String8, ImpliedFeature>* impliedFeatures = NULL) {
6452c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    printf("feature-group: label='%s'\n", grp.label.string());
6462c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
647d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    if (grp.openGLESVersion > 0) {
648d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        printf("  uses-gl-es: '0x%x'\n", grp.openGLESVersion);
649d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    }
650d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
6512c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numFeatures = grp.features.size();
6522c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numFeatures; i++) {
6532c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        if (!grp.features[i]) {
6542c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            continue;
6552c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6562c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6572c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const String8& featureName = grp.features.keyAt(i);
6582c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("  uses-feature: name='%s'\n",
6592c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                ResTable::normalizeForOutput(featureName.string()).string());
6602c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6612c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numImpliedFeatures =
6632c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        (impliedFeatures != NULL) ? impliedFeatures->size() : 0;
6642c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numImpliedFeatures; i++) {
6652c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i);
6662c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        if (grp.features.indexOfKey(impliedFeature.name) >= 0) {
6672c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // The feature is explicitly set, no need to use implied
6682c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // definition.
6692c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            continue;
6702c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6712c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6722c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        String8 printableFeatureName(ResTable::normalizeForOutput(
6732c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    impliedFeature.name.string()));
6742c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("  uses-feature: name='%s'\n", printableFeatureName.string());
6752c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("  uses-implied-feature: name='%s' reason='",
6762c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printableFeatureName.string());
6772c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const size_t numReasons = impliedFeature.reasons.size();
6782c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        for (size_t j = 0; j < numReasons; j++) {
6792c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            printf("%s", impliedFeature.reasons[j].string());
6802c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            if (j + 2 < numReasons) {
6812c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", ");
6822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            } else if (j + 1 < numReasons) {
6832c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", and ");
6842c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            }
6852c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6862c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("'\n");
6872c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6882c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
6892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addParentFeatures(FeatureGroup* grp, const String8& name) {
6912c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (name == "android.hardware.camera.autofocus" ||
6922c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.camera.flash") {
6932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.camera"), true);
6942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.location.gps" ||
6952c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.location.network") {
6962c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.location"), true);
6972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch") {
6982c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), true);
6992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
7002c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen.multitouch"), true);
7012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), true);
702d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    } else if (name == "android.hardware.opengles.aep") {
703d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        const int openGLESVersion31 = 0x00030001;
704d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        if (openGLESVersion31 > grp->openGLESVersion) {
705d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski            grp->openGLESVersion = openGLESVersion31;
706d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        }
7072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
7082c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
7092c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "dump" command, to extract select data from an archive.
712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiextern char CONSOLE_DATA[2925]; // see EOF
714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doDump(Bundle* bundle)
715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump option specified\n");
720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump file specified\n");
725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* option = bundle->getFileSpecEntry(0);
729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* filename = bundle->getFileSpecEntry(1);
730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    AssetManager assets;
732f85e41f29a0e9313c2d4725f9d9648591ea49f3bNarayan Kamath    int32_t assetsCookie;
733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make a dummy config for retrieving resources...  we need to supply
739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // non-default values for some configs so that we can retrieve resources
740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // in the app that don't have a default.  The most important of these is
741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the API version because key resources like icons will have an implicit
742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // version if they are using newer config types like density.
743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_config config;
74491447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath    memset(&config, 0, sizeof(ResTable_config));
745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[0] = 'e';
746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[1] = 'n';
747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[0] = 'U';
748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[1] = 'S';
749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.orientation = ResTable_config::ORIENTATION_PORT;
750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.density = ResTable_config::DENSITY_MEDIUM;
751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.sdkVersion = 10000; // Very high.
752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenWidthDp = 320;
753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenHeightDp = 480;
754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.smallestScreenWidthDp = 320;
755c2dea8daea2ae0001d56689d96ce1066012b7b40Adam Lesinski    config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL;
756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets.setConfiguration(config);
757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ResTable& res = assets.getResources(false);
759282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (&res == NULL) {
760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
76163e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        return 1;
76225e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski    } else if (res.getError() != NO_ERROR) {
76325e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
76463e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        return 1;
76563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    }
76663e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski
7672cb761e3ddb9d68ab430013e9cd15ecaab9fbc62Adam Lesinski    // The dynamicRefTable can be null if there are no resources for this asset cookie.
7682cb761e3ddb9d68ab430013e9cd15ecaab9fbc62Adam Lesinski    // This fine.
76963e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie);
770282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
77163e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    Asset* asset = NULL;
77263e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski
773282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strcmp("resources", option) == 0) {
774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        res.print(bundle->getValues());
776282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("strings", option) == 0) {
779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResStringPool* pool = res.getTableStringBlock(0);
780282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printStringPool(pool);
781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmltree", option) == 0) {
783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
79063e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            ResXMLTree tree(dynamicRefTable);
79163e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
795282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.restart();
803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
804282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.uninit();
805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmlstrings", option) == 0) {
810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
81763e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
82363e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            ResXMLTree tree(dynamicRefTable);
824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
826282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
827282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
828282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printStringPool(&tree.getStrings());
830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
83563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER);
836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (asset == NULL) {
837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
84163e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        ResXMLTree tree(dynamicRefTable);
842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.setTo(asset->getBuffer(true),
843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       asset->getLength()) != NO_ERROR) {
844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        tree.restart();
848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcmp("permissions", option) == 0) {
850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
8629cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                const char16_t* ctag16 = tree.getElementName(&len);
8639cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                if (ctag16 == NULL) {
8649cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
8659cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    goto bail;
8669cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                }
8679cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                String8 tag(ctag16);
868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d tag %s\n", depth, tag.string());
869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 pkg = getAttribute(tree, NULL, "package", NULL);
8752675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "permission") {
877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 name = getAttribute(tree, NAME_ATTR, &error);
879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
8832675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("permission: %s\n",
8842675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(name.string()).string());
885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "uses-permission") {
886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 name = getAttribute(tree, NAME_ATTR, &error);
888282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
889282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
89258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(name,
89358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
89458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
895282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
896282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
897282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badging", option) == 0) {
898282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<String8> locales;
899282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getLocales(&locales);
900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
901282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            SortedVector<int> densities;
904282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NC = configs.size();
905282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NC; i++) {
906282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int dens = configs[i].density;
907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dens == 0) {
908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    dens = 160;
909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                densities.add(dens);
911282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 error;
917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinActivity = false;
918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isMainActivity = false;
919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isLauncherActivity = false;
9200a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            bool isLeanbackLauncherActivity = false;
921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isSearchable = false;
922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinApplication = false;
923ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            bool withinSupportsInput = false;
9242c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            bool withinFeatureGroup = false;
925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinReceiver = false;
926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinService = false;
9279d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool withinProvider = false;
928282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinIntentFilter = false;
929282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasMainActivity = false;
930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherActivities = false;
931282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherReceivers = false;
932282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherServices = false;
9339d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasIntentFilter = false;
9349d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWallpaperService = false;
936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasImeService = false;
937a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasAccessibilityService = false;
938a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasPrintService = false;
939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWidgetReceivers = false;
940a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasDeviceAdminReceiver = false;
94194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasPaymentService = false;
9429d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasDocumentsProvider = false;
9439d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasCameraActivity = false;
9449d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasCameraSecureActivity = false;
9459d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasLauncher = false;
9469d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasNotificationListenerService = false;
947eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool hasDreamService = false;
9489d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actMainActivity = false;
950282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWidgetReceivers = false;
951a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actDeviceAdminEnabled = false;
952282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actImeService = false;
953282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWallpaperService = false;
954a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actAccessibilityService = false;
955a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actPrintService = false;
95694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actHostApduService = false;
95794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actOffHostApduService = false;
9589d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actDocumentsProvider = false;
9599d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actNotificationListenerService = false;
960eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool actDreamService = false;
9619d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actCamera = false;
9629d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actCameraSecure = false;
9639d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool catLauncher = false;
96494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaHostPaymentCategory = false;
96594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaOffHostPaymentCategory = false;
966a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
967a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // These permissions are required by services implementing services
968a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // the system binds to (IME, Accessibility, PrintServices, etc.)
969a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindDeviceAdminPermission = false;
970a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindInputMethodPermission = false;
971a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindAccessibilityServicePermission = false;
972a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindPrintServicePermission = false;
97394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasBindNfcServicePermission = false;
9749d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasRequiredSafAttributes = false;
9759d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasBindNotificationListenerServicePermission = false;
976eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool hasBindDreamServicePermission = false;
977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // These two implement the implicit permissions that are granted
979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // to pre-1.6 applications.
980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteExternalStoragePermission = false;
981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadPhoneStatePermission = false;
982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If an app requests write storage, they will also get read storage.
984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadExternalStoragePermission = false;
985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Implement transition to read and write call log.
987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadContactsPermission = false;
988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteContactsPermission = false;
989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadCallLogPermission = false;
990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteCallLogPermission = false;
991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
992e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            // If an app declares itself as multiArch, we report the
993e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            // native libraries differently.
994e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            bool hasMultiArch = false;
995e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This next group of variables is used to implement a group of
997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // backward-compatibility heuristics necessitated by the addition of
998282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // some new uses-feature constants in 2.1 and 2.2. In most cases, the
999282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // heuristic is "if an app requests a permission but doesn't explicitly
1000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // request the corresponding <uses-feature>, presume it's there anyway".
10012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // 2.2 also added some other features that apps can request, but that
1003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // have no corresponding permission, so we cannot implement any
1004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // back-compatibility heuristic for them. The below are thus unnecessary
1005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // (but are retained here for documentary purposes.)
1006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specCompassFeature = false;
1007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAccelerometerFeature = false;
1008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specProximityFeature = false;
1009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAmbientLightFeature = false;
1010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specLiveWallpaperFeature = false;
1011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int targetSdk = 0;
1013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int smallScreen = 1;
1014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int normalScreen = 1;
1015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largeScreen = 1;
1016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int xlargeScreen = 1;
1017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int anyDensity = 1;
1018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int requiresSmallestWidthDp = 0;
1019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int compatibleWidthLimitDp = 0;
1020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largestWidthLimitDp = 0;
1021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 pkg;
1022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityName;
1023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityLabel;
1024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityIcon;
10250a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            String8 activityBanner;
1026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 receiverName;
1027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 serviceName;
1028ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            Vector<String8> supportedInput;
10292c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
10302c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            FeatureGroup commonFeatures;
10312c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            Vector<FeatureGroup> featureGroups;
10322c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            KeyedVector<String8, ImpliedFeature> impliedFeatures;
10332c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
1036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
1037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (depth < 2) {
1038ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if (withinSupportsInput && !supportedInput.isEmpty()) {
1039ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("supports-input: '");
1040ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            const size_t N = supportedInput.size();
1041ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            for (size_t i=0; i<N; i++) {
10422675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                printf("%s", ResTable::normalizeForOutput(
10432675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        supportedInput[i].string()).string());
1044ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (i != N - 1) {
1045ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("' '");
1046ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else {
1047ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("'\n");
1048ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1049ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1050ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            supportedInput.clear();
1051ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        }
1052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = false;
1053ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = false;
10542c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        withinFeatureGroup = false;
1055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 3) {
10560a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                        if (withinActivity && isMainActivity) {
10572675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            String8 aName(getComponentName(pkg, activityName));
10580a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (isLauncherActivity) {
10590a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf("launchable-activity:");
10609eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                if (aName.length() > 0) {
10619eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                    printf(" name='%s' ",
10629eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                            ResTable::normalizeForOutput(aName.string()).string());
10630a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                }
10640a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf(" label='%s' icon='%s'\n",
10659eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
10669eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityIcon.string()).string());
10670a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            }
10680a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (isLeanbackLauncherActivity) {
10690a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf("leanback-launchable-activity:");
10709eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                if (aName.length() > 0) {
10719eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                    printf(" name='%s' ",
10729eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                            ResTable::normalizeForOutput(aName.string()).string());
10730a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                }
10740a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf(" label='%s' icon='%s' banner='%s'\n",
10759eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
10769eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityIcon.string()).string(),
10779eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityBanner.string()).string());
1078282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1079282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (!hasIntentFilter) {
1081282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherActivities |= withinActivity;
1082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherReceivers |= withinReceiver;
1083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherServices |= withinService;
108494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        } else {
108594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (withinService) {
108694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
108794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        hasBindNfcServicePermission);
108894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
108994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        hasBindNfcServicePermission);
109094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
1091282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1092282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinActivity = false;
1093282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinService = false;
1094282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinReceiver = false;
10959d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        withinProvider = false;
1096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasIntentFilter = false;
10970a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                        isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false;
1098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 4) {
1099282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (withinIntentFilter) {
1100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (withinActivity) {
1101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasMainActivity |= actMainActivity;
11029d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasLauncher |= catLauncher;
11039d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasCameraActivity |= actCamera;
11049d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasCameraSecureActivity |= actCameraSecure;
11059d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasOtherActivities |= !actMainActivity && !actCamera && !actCameraSecure;
1106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinReceiver) {
1107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWidgetReceivers |= actWidgetReceivers;
1108a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
1109a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindDeviceAdminPermission);
1110a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled);
1111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinService) {
1112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasImeService |= actImeService;
1113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWallpaperService |= actWallpaperService;
1114a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasAccessibilityService |= (actAccessibilityService &&
1115a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindAccessibilityServicePermission);
1116a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasPrintService |= (actPrintService && hasBindPrintServicePermission);
11179d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasNotificationListenerService |= actNotificationListenerService &&
11189d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        hasBindNotificationListenerServicePermission;
1119eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                hasDreamService |= actDreamService && hasBindDreamServicePermission;
1120a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasOtherServices |= (!actImeService && !actWallpaperService &&
112194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        !actAccessibilityService && !actPrintService &&
11229d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        !actHostApduService && !actOffHostApduService &&
11239d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        !actNotificationListenerService);
11249d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (withinProvider) {
11259d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasDocumentsProvider |= actDocumentsProvider && hasRequiredSafAttributes;
1126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinIntentFilter = false;
1129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
1131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
1133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
1134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
11369cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski
11379cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                const char16_t* ctag16 = tree.getElementName(&len);
11389cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                if (ctag16 == NULL) {
11399cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
11409cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    goto bail;
11419cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                }
11429cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                String8 tag(ctag16);
1143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d,  %s\n", depth, tag.string());
1144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
1145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
1146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
1147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    pkg = getAttribute(tree, NULL, "package", NULL);
11502675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("package: name='%s' ",
11512675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(pkg.string()).string());
1152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error);
1153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
1154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string());
1155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (versionCode > 0) {
1158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='%d' ", versionCode);
1159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
1160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='' ");
1161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error);
1163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
1164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string());
1165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
116725d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    printf("versionName='%s'",
11682675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(versionName.string()).string());
116925d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski
117025d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    String8 splitName = getAttribute(tree, NULL, "split", NULL);
117125d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    if (!splitName.isEmpty()) {
117225d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                        printf(" split='%s'", ResTable::normalizeForOutput(
117325d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                                    splitName.string()).string());
117425d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    }
117525d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    printf("\n");
1176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2) {
1177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinApplication = false;
1178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag == "application") {
1179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = true;
1180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 label;
1182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t NL = locales.size();
1183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<NL; i++) {
1184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char* localeStr =  locales[i].string();
1185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setLocale(localeStr != NULL ? localeStr : "");
1186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (llabel != "") {
1188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                if (localeStr == NULL || strlen(localeStr) == 0) {
1189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    label = llabel;
11902675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    printf("application-label:'%s'\n",
11912675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                            ResTable::normalizeForOutput(llabel.string()).string());
1192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                } else {
1193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    if (label == "") {
1194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        label = llabel;
1195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    }
1196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    printf("application-label-%s:'%s'\n", localeStr,
11972675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                           ResTable::normalizeForOutput(llabel.string()).string());
1198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResTable_config tmpConfig = config;
1203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t ND = densities.size();
1204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<ND; i++) {
1205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            tmpConfig.density = densities[i];
1206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setConfiguration(tmpConfig);
1207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (icon != "") {
12092675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                printf("application-icon-%d:'%s'\n", densities[i],
12102675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(icon.string()).string());
1211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        assets.setConfiguration(config);
1214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
1218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
1221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
1223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
12252675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        printf("application: label='%s' ",
12262675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                ResTable::normalizeForOutput(label.string()).string());
12272675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        printf("icon='%s'\n", ResTable::normalizeForOutput(icon.string()).string());
1228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (testOnly != 0) {
1229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("testOnly='%d'\n", testOnly);
1230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0);
1233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string());
1235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (debuggable != 0) {
1238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("application-debuggable\n");
1239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1240e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
1241e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // We must search by name because the multiArch flag hasn't been API
1242e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // frozen yet.
1243e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        int32_t multiArchIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
1244e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                "multiArch");
1245e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (multiArchIndex >= 0) {
1246e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            Res_value value;
1247e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            if (tree.getAttributeValue(multiArchIndex, &value) != NO_ERROR) {
1248e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                if (value.dataType >= Res_value::TYPE_FIRST_INT &&
1249e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                        value.dataType <= Res_value::TYPE_LAST_INT) {
1250e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                    hasMultiArch = value.data;
1251e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                }
1252e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            }
1253e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
1254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-sdk") {
1255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
1256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
1258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
1259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
1260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
1261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
1262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut") targetSdk = 4;
12652675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("sdkVersion:'%s'\n",
12662675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
1268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            targetSdk = code;
1269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("sdkVersion:'%d'\n", code);
1270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1);
1272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (code != -1) {
1273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("maxSdkVersion:'%d'\n", code);
1274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
1276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
1278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
1279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
1280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
1281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
1282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
12852675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("targetSdkVersion:'%s'\n",
12862675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
1288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (targetSdk < code) {
1289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                targetSdk = code;
1290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("targetSdkVersion:'%d'\n", code);
1292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-configuration") {
1294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqTouchScreen = getIntegerAttribute(tree,
1295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_TOUCH_SCREEN_ATTR, NULL, 0);
1296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqKeyboardType = getIntegerAttribute(tree,
1297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
1298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqHardKeyboard = getIntegerAttribute(tree,
1299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_HARD_KEYBOARD_ATTR, NULL, 0);
1300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqNavigation = getIntegerAttribute(tree,
1301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_NAVIGATION_ATTR, NULL, 0);
1302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqFiveWayNav = getIntegerAttribute(tree,
1303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
1304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("uses-configuration:");
1305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqTouchScreen != 0) {
1306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqTouchScreen='%d'", reqTouchScreen);
1307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqKeyboardType != 0) {
1309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqKeyboardType='%d'", reqKeyboardType);
1310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqHardKeyboard != 0) {
1312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqHardKeyboard='%d'", reqHardKeyboard);
1313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqNavigation != 0) {
1315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqNavigation='%d'", reqNavigation);
1316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqFiveWayNav != 0) {
1318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqFiveWayNav='%d'", reqFiveWayNav);
1319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("\n");
1321ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    } else if (tag == "supports-input") {
1322ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = true;
1323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-screens") {
1324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        smallScreen = getIntegerAttribute(tree,
1325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                SMALL_SCREEN_ATTR, NULL, 1);
1326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        normalScreen = getIntegerAttribute(tree,
1327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                NORMAL_SCREEN_ATTR, NULL, 1);
1328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        largeScreen = getIntegerAttribute(tree,
1329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                LARGE_SCREEN_ATTR, NULL, 1);
1330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        xlargeScreen = getIntegerAttribute(tree,
1331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                XLARGE_SCREEN_ATTR, NULL, 1);
1332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        anyDensity = getIntegerAttribute(tree,
1333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                ANY_DENSITY_ATTR, NULL, 1);
1334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        requiresSmallestWidthDp = getIntegerAttribute(tree,
1335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0);
1336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        compatibleWidthLimitDp = getIntegerAttribute(tree,
1337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0);
1338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        largestWidthLimitDp = getIntegerAttribute(tree,
1339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0);
13402c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    } else if (tag == "feature-group") {
13412c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        withinFeatureGroup = true;
13422c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        FeatureGroup group;
13432c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        group.label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
13442c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        if (error != "") {
13452c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:label' attribute:"
13462c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    " %s\n", error.string());
13472c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            goto bail;
13482c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
13492c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        featureGroups.add(group);
13502c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-feature") {
1352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            int req = getIntegerAttribute(tree,
1355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    REQUIRED_ATTR, NULL, 1);
1356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
13572c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            commonFeatures.features.add(name, req);
13582c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            if (req) {
13592c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addParentFeatures(&commonFeatures, name);
1360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            int vers = getIntegerAttribute(tree,
1363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    GL_ES_VERSION_ATTR, &error);
1364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error == "") {
1365d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                if (vers > commonFeatures.openGLESVersion) {
1366d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    commonFeatures.openGLESVersion = vers;
1367d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                }
1368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-permission") {
1371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "android.permission.CAMERA") {
1374d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.camera",
13752c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13762c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
13782c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location.gps",
13792c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13802c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
13812c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
13822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13832c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
13852c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
13862c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13872c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
13892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location.network",
13902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13912c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
13922c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
13932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
1396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.INSTALL_LOCATION_PROVIDER") {
13972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
13982c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.BLUETOOTH" ||
1401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.BLUETOOTH_ADMIN") {
14022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                if (targetSdk > 4) {
14032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
14042c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            String8::format("requested %s permission", name.string())
14052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            .string());
14062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
14072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            "targetSdkVersion > 4");
14082c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                }
1409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.RECORD_AUDIO") {
14102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.microphone",
14112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
1414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CHANGE_WIFI_STATE" ||
1415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
14162c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.wifi",
14172c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14182c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.CALL_PHONE" ||
1420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CALL_PRIVILEGED" ||
1421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.MODIFY_PHONE_STATE" ||
1422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.PROCESS_OUTGOING_CALLS" ||
1423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.READ_SMS" ||
1424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_SMS" ||
1425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_MMS" ||
1426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_WAP_PUSH" ||
1427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.SEND_SMS" ||
1428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.WRITE_APN_SETTINGS" ||
1429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.WRITE_SMS") {
14302c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.telephony",
14312c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8("requested a telephony permission").string());
1432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
1433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteExternalStoragePermission = true;
1434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
1435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadExternalStoragePermission = true;
1436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_PHONE_STATE") {
1437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadPhoneStatePermission = true;
1438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_CONTACTS") {
1439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadContactsPermission = true;
1440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_CONTACTS") {
1441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteContactsPermission = true;
1442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_CALL_LOG") {
1443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadCallLogPermission = true;
1444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_CALL_LOG") {
1445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteCallLogPermission = true;
1446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
144758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
144858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            printUsesPermission(name,
144958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                                    getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
145058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                                    getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
145158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                       } else {
1452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-package") {
1457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
14592675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("uses-package:'%s'\n",
14602675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "original-package") {
1467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
14692675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("original-package:'%s'\n",
14702675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-gl-texture") {
1477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
14792675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("supports-gl-texture:'%s'\n",
14802675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "compatible-screens") {
14879cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        printCompatibleScreens(tree, &error);
14889cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        if (error != "") {
14899cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                            fprintf(stderr, "ERROR getting compatible screens: %s\n",
14909cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                                    error.string());
14919cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                            goto bail;
14929cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        }
1493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        depth--;
1494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "package-verifier") {
1495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error);
1498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (publicKey != "" && error == "") {
1499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                printf("package-verifier: name='%s' publicKey='%s'\n",
15002675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(name.string()).string(),
15012675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(publicKey.string()).string());
1502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1505ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                } else if (depth == 3) {
1506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinActivity = false;
1507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinReceiver = false;
1508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinService = false;
15099d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    withinProvider = false;
1510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasIntentFilter = false;
151194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasMetaHostPaymentCategory = false;
151294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasMetaOffHostPaymentCategory = false;
151394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindDeviceAdminPermission = false;
151494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindInputMethodPermission = false;
151594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindAccessibilityServicePermission = false;
151694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindPrintServicePermission = false;
151794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindNfcServicePermission = false;
15189d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    hasRequiredSafAttributes = false;
15199d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    hasBindNotificationListenerServicePermission = false;
1520eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                    hasBindDreamServicePermission = false;
1521ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    if (withinApplication) {
1522ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if(tag == "activity") {
1523ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinActivity = true;
1524ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityName = getAttribute(tree, NAME_ATTR, &error);
1525ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1526ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1527ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1528ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1529ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1531ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1532ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1533ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
1534ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1535ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1536ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1538ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1539ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1540ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
1541ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1542ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1543ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
15450a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            activityBanner = getResolvedAttribute(&res, tree, BANNER_ATTR, &error);
15460a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (error != "") {
15470a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
15480a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                        error.string());
15490a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                goto bail;
15500a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            }
15510a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn
1552ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            int32_t orien = getResolvedIntegerAttribute(&res, tree,
1553ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    SCREEN_ORIENTATION_ATTR, &error);
1554ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error == "") {
1555ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (orien == 0 || orien == 6 || orien == 8) {
1556ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests landscape, sensorLandscape, or reverseLandscape.
15572c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.landscape",
15582c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            "one or more activities have specified a landscape orientation");
1559ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else if (orien == 1 || orien == 7 || orien == 9) {
1560ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests portrait, sensorPortrait, or reversePortrait.
15612c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.portrait",
15622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            "one or more activities have specified a portrait orientation");
1563ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1565ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "uses-library") {
1566ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
1567ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1568ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1569ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for uses-library"
1570ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1571ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1572ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1573ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            int req = getIntegerAttribute(tree,
1574ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    REQUIRED_ATTR, NULL, 1);
1575ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("uses-library%s:'%s'\n",
15762675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    req ? "" : "-not-required", ResTable::normalizeForOutput(
15772675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                            libraryName.string()).string());
1578ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "receiver") {
1579ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinReceiver = true;
1580ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            receiverName = getAttribute(tree, NAME_ATTR, &error);
1581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1582ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1583ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1584ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for receiver:"
1585ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1586ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1587ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1588a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1589a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1590a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1591a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_DEVICE_ADMIN") {
1592a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindDeviceAdminPermission = true;
1593a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1594a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
1595a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1596a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        " receiver '%s': %s\n", receiverName.string(), error.string());
1597a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
1598ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "service") {
1599ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinService = true;
1600ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            serviceName = getAttribute(tree, NAME_ATTR, &error);
1601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1602ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1603ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1604ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "service:%s\n", error.string());
1605ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1606ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1607a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1608a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1609a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1610a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_INPUT_METHOD") {
1611a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindInputMethodPermission = true;
1612a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
1613a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindAccessibilityServicePermission = true;
1614a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
1615a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindPrintServicePermission = true;
161694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                } else if (permission == "android.permission.BIND_NFC_SERVICE") {
161794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasBindNfcServicePermission = true;
16189d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                } else if (permission == "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
16199d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                    hasBindNotificationListenerServicePermission = true;
1620eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                } else if (permission == "android.permission.BIND_DREAM_SERVICE") {
1621eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                    hasBindDreamServicePermission = true;
1622a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1623a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
1624a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1625a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        " service '%s': %s\n", serviceName.string(), error.string());
1626a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
16279d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        } else if (tag == "provider") {
16289d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            withinProvider = true;
16299d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16309d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            bool exported = getResolvedIntegerAttribute(&res, tree, EXPORTED_ATTR, &error);
16319d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
16329d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:exported' attribute for provider:"
16339d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        " %s\n", error.string());
16349d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
16359d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
16369d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16379d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            bool grantUriPermissions = getResolvedIntegerAttribute(&res, tree,
16389d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                    GRANT_URI_PERMISSIONS_ATTR, &error);
16399d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
16409d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:grantUriPermissions' attribute for provider:"
16419d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        " %s\n", error.string());
16429d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
16439d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
16449d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16459d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            String8 permission = getResolvedAttribute(&res, tree, PERMISSION_ATTR, &error);
16469d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
16479d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for provider:"
16489d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        " %s\n", error.string());
16499d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
16509d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
16519d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16529d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            hasRequiredSafAttributes |= exported && grantUriPermissions &&
16539d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                permission == "android.permission.MANAGE_DOCUMENTS";
16549d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
1655ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
1656b71adb6571aa740f4fa794602133f708e1b96545Adam Lesinski                            String8 metaDataName = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
1657ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1658ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1659ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "meta-data:%s\n", error.string());
1660ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1661ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
16622675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("meta-data: name='%s' ",
16632675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(metaDataName.string()).string());
166476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                            printResolvedResourceAttribute(&res, tree, VALUE_ATTR, String8("value"),
166576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                    &error);
1666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
166776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                // Try looking for a RESOURCE_ATTR
166876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                error = "";
166976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                printResolvedResourceAttribute(&res, tree, RESOURCE_ATTR,
167076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                        String8("resource"), &error);
1671ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (error != "") {
167276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                    fprintf(stderr, "ERROR getting 'android:value' or "
167376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                            "'android:resource' attribute for "
167476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                            "meta-data:%s\n", error.string());
1675ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    goto bail;
1676ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1677ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
167876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                            printf("\n");
1679ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (withinSupportsInput && tag == "input-type") {
1680ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 name = getAttribute(tree, NAME_ATTR, &error);
1681ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (name != "" && error == "") {
1682ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                supportedInput.add(name);
1683ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            } else {
1684ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1685ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1686282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1687282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
16892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    } else if (withinFeatureGroup && tag == "uses-feature") {
1690d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        FeatureGroup& top = featureGroups.editTop();
1691d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
16922c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        String8 name = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
1693d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        if (name != "" && error == "") {
1694d3edfde51bd069a63e820282421d1a534fcf00ceAdam Lesinski                            top.features.add(name, true);
1695d3edfde51bd069a63e820282421d1a534fcf00ceAdam Lesinski                            addParentFeatures(&top, name);
1696d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        } else {
1697d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            int vers = getIntegerAttribute(tree, GL_ES_VERSION_ATTR, &error);
1698d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            if (error == "") {
1699d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                if (vers > top.openGLESVersion) {
1700d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    top.openGLESVersion = vers;
1701d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                }
1702d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            }
17032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
1704a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
170594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                } else if (depth == 4) {
170694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (tag == "intent-filter") {
170794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        hasIntentFilter = true;
170894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        withinIntentFilter = true;
170994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actMainActivity = false;
171094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actWidgetReceivers = false;
171194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actImeService = false;
171294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actWallpaperService = false;
171394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actAccessibilityService = false;
171494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actPrintService = false;
171594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actDeviceAdminEnabled = false;
171694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actHostApduService = false;
171794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actOffHostApduService = false;
17189d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actDocumentsProvider = false;
17199d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actNotificationListenerService = false;
1720eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                        actDreamService = false;
17219d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actCamera = false;
17229d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actCameraSecure = false;
17239d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        catLauncher = false;
172494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    } else if (withinService && tag == "meta-data") {
172594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
172694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (error != "") {
172794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute for"
172894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
172994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            goto bail;
173094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        }
173194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
173294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (name == "android.nfc.cardemulation.host_apdu_service" ||
173394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                name == "android.nfc.cardemulation.off_host_apdu_service") {
173494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            bool offHost = true;
173594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (name == "android.nfc.cardemulation.host_apdu_service") {
173694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                offHost = false;
173794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
173894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
173994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            String8 xmlPath = getResolvedAttribute(&res, tree, RESOURCE_ATTR, &error);
174094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (error != "") {
174194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:resource' attribute for"
174294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
174394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                goto bail;
174494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
174594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
174694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
174794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    offHost, &error);
174894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (error != "") {
174994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                fprintf(stderr, "ERROR getting AID category for service '%s'\n",
175094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        serviceName.string());
175194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                goto bail;
175294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
175394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
175494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            const size_t catLen = categories.size();
175594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            for (size_t i = 0; i < catLen; i++) {
175694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                bool paymentCategory = (categories[i] == "payment");
175794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                if (offHost) {
175894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasMetaOffHostPaymentCategory |= paymentCategory;
175994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                } else {
176094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasMetaHostPaymentCategory |= paymentCategory;
176194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                }
176294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
176394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        }
176494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
1765a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                } else if ((depth == 5) && withinIntentFilter) {
1766a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    String8 action;
1767a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "action") {
1768a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        action = getAttribute(tree, NAME_ATTR, &error);
1769a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1770a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1771a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1772a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1773a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1774a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1775a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1776a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.intent.action.MAIN") {
1777a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isMainActivity = true;
1778a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actMainActivity = true;
17799d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (action == "android.media.action.STILL_IMAGE_CAMERA" ||
17809d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                    action == "android.media.action.VIDEO_CAMERA") {
17819d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actCamera = true;
17829d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (action == "android.media.action.STILL_IMAGE_CAMERA_SECURE") {
17839d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actCameraSecure = true;
1784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1785a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinReceiver) {
1786a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
1787a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWidgetReceivers = true;
1788a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
1789a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actDeviceAdminEnabled = true;
1790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1791a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinService) {
1792a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.view.InputMethod") {
1793a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actImeService = true;
1794a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.service.wallpaper.WallpaperService") {
1795a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWallpaperService = true;
1796a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.accessibilityservice.AccessibilityService") {
1797a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actAccessibilityService = true;
1798a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.printservice.PrintService") {
1799a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actPrintService = true;
180094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            } else if (action == "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
180194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                actHostApduService = true;
180294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            } else if (action == "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
180394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                actOffHostApduService = true;
18049d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (action == "android.service.notification.NotificationListenerService") {
18059d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actNotificationListenerService = true;
1806eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                            } else if (action == "android.service.dreams.DreamService") {
1807eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                actDreamService = true;
18089d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
18099d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        } else if (withinProvider) {
18109d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (action == "android.content.action.DOCUMENTS_PROVIDER") {
18119d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actDocumentsProvider = true;
1812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1814a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (action == "android.intent.action.SEARCH") {
1815a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            isSearchable = true;
1816a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1817a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
1818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1819a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "category") {
1820a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        String8 category = getAttribute(tree, NAME_ATTR, &error);
1821a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1822a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'name' attribute: %s\n",
1823a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1824a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1825a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1826a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1827a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (category == "android.intent.category.LAUNCHER") {
1828a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isLauncherActivity = true;
18290a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            } else if (category == "android.intent.category.LEANBACK_LAUNCHER") {
18300a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                isLeanbackLauncherActivity = true;
18319d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (category == "android.intent.category.HOME") {
18329d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                catLauncher = true;
1833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-1.6 implicitly granted permission compatibility logic
1840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 4) {
1841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteExternalStoragePermission) {
184258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
184358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
184458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 4"));
1845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasWriteExternalStoragePermission = true;
1846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadPhoneStatePermission) {
184858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.READ_PHONE_STATE"));
184958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"),
185058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 4"));
1851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If the application has requested WRITE_EXTERNAL_STORAGE, we will
1855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // force them to always take READ_EXTERNAL_STORAGE as well.  We always
1856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // do this (regardless of target API version) because we can't have
1857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // an app with write permission but not read permission.
1858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
185958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"));
186058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
186158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                        String8("requested WRITE_EXTERNAL_STORAGE"));
1862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-JellyBean call log permission compatibility.
1865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 16) {
1866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadCallLogPermission && hasReadContactsPermission) {
186758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.READ_CALL_LOG"));
186858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
186958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 16 and requested READ_CONTACTS"));
1870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
187258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.WRITE_CALL_LOG"));
187358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"),
187458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 16 and requested WRITE_CONTACTS"));
1875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
18782c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            addImpliedFeature(&impliedFeatures, "android.hardware.touchscreen",
18792c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    "default feature for all apps");
18802c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
18812c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            const size_t numFeatureGroups = featureGroups.size();
18822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            if (numFeatureGroups == 0) {
18832c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                // If no <feature-group> tags were defined, apply auto-implied features.
18842c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printFeatureGroup(commonFeatures, &impliedFeatures);
18852c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
18862c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            } else {
18872c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                // <feature-group> tags are defined, so we ignore implied features and
18882c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                for (size_t i = 0; i < numFeatureGroups; i++) {
18892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    FeatureGroup& grp = featureGroups.editItemAt(i);
18902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1891d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                    if (commonFeatures.openGLESVersion > grp.openGLESVersion) {
1892d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        grp.openGLESVersion = commonFeatures.openGLESVersion;
1893d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                    }
1894d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
18952c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    // Merge the features defined in the top level (not inside a <feature-group>)
18962c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    // with this feature group.
18972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    const size_t numCommonFeatures = commonFeatures.features.size();
18982c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    for (size_t j = 0; j < numCommonFeatures; j++) {
18992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) {
1900d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            grp.features.add(commonFeatures.features.keyAt(j),
1901d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    commonFeatures.features[j]);
19022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
1903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1904282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                   if (!grp.features.isEmpty()) {
19062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        printFeatureGroup(grp);
19072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    }
1908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWidgetReceivers) {
19139d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("app-widget");
1914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1915a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasDeviceAdminReceiver) {
19169d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("device-admin");
1917a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
1918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasImeService) {
19199d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("ime");
1920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWallpaperService) {
19229d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("wallpaper");
1923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1924a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasAccessibilityService) {
19259d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("accessibility");
1926a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
1927a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasPrintService) {
19289d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("print-service");
1929a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
193094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (hasPaymentService) {
19319d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("payment");
19329d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19339d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (isSearchable) {
19349d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("search");
19359d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19369d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasDocumentsProvider) {
19379d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("document-provider");
19389d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19399d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasLauncher) {
19409d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("launcher");
19419d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19429d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasNotificationListenerService) {
19439d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("notification-listener");
19449d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
1945eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            if (hasDreamService) {
1946eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                printComponentPresence("dream");
1947eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            }
19489d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasCameraActivity) {
19499d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("camera");
19509d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19519d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasCameraSecureActivity) {
19529d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("camera-secure");
19539d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19549d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
19559d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasMainActivity) {
19569d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printf("main\n");
195794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
1958282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherActivities) {
1959282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-activities\n");
1960282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
19619d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski             if (hasOtherReceivers) {
1962282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-receivers\n");
1963282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1964282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherServices) {
1965282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-services\n");
1966282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // For modern apps, if screen size buckets haven't been specified
1969282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // but the new width ranges have, then infer the buckets from them.
1970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
1971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    && requiresSmallestWidthDp > 0) {
1972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int compatWidth = compatibleWidthLimitDp;
1973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (compatWidth <= 0) {
1974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    compatWidth = requiresSmallestWidthDp;
1975282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1976282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
1977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = -1;
1978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = 0;
1980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
1982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = -1;
1983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = 0;
1985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
1987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = -1;
1988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = 0;
1990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
1992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = -1;
1993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = 0;
1995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1998282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Determine default values for any unspecified screen sizes,
1999282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // based on the target SDK of the package.  As of 4 (donut)
2000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // the screen size support was introduced, so all default to
2001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // enabled.
2002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0) {
2003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                smallScreen = targetSdk >= 4 ? -1 : 0;
2004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen > 0) {
2006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                normalScreen = -1;
2007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen > 0) {
2009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                largeScreen = targetSdk >= 4 ? -1 : 0;
2010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen > 0) {
2012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Introduced in Gingerbread.
2013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                xlargeScreen = targetSdk >= 9 ? -1 : 0;
2014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (anyDensity > 0) {
2016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
2017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        || compatibleWidthLimitDp > 0) ? -1 : 0;
2018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-screens:");
2020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen != 0) {
2021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'small'");
2022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen != 0) {
2024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'normal'");
2025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen != 0) {
2027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'large'");
2028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen != 0) {
2030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'xlarge'");
2031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
2034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (requiresSmallestWidthDp > 0) {
2035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
2036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (compatibleWidthLimitDp > 0) {
2038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
2039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largestWidthLimitDp > 0) {
2041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
2042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2043282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2044282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("locales:");
2045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NL = locales.size();
2046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NL; i++) {
2047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const char* localeStr =  locales[i].string();
2048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (localeStr == NULL || strlen(localeStr) == 0) {
2049282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    localeStr = "--_--";
2050282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2051282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'", localeStr);
2052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2053282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2054282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("densities:");
2056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t ND = densities.size();
2057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<ND; i++) {
2058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%d'", densities[i]);
2059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2061282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
2063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (dir != NULL) {
2064282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dir->getFileCount() > 0) {
2065e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    SortedVector<String8> architectures;
2066282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    for (size_t i=0; i<dir->getFileCount(); i++) {
2067e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        architectures.add(ResTable::normalizeForOutput(
2068e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                dir->getFileName(i).string()));
2069e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    }
2070e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2071e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    bool outputAltNativeCode = false;
2072e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // A multiArch package is one that contains 64-bit and
2073e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 32-bit versions of native code and expects 3rd-party
2074e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // apps to load these native code libraries. Since most
2075e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 64-bit systems also support 32-bit apps, the apps
2076e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // loading this multiArch package's code may be either
2077e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 32-bit or 64-bit.
2078e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    if (hasMultiArch) {
2079e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // If this is a multiArch package, report the 64-bit
2080e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // version only. Then as a separate entry, report the
2081e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // rest.
2082e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        //
2083e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // If we report the 32-bit architecture, this APK will
2084e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // be installed on a 32-bit device, causing a large waste
2085e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // of bandwidth and disk space. This assumes that
2086e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // the developer of the multiArch package has also
2087e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // made a version that is 32-bit only.
2088e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        String8 intel64("x86_64");
2089e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        String8 arm64("arm64-v8a");
2090e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        ssize_t index = architectures.indexOf(intel64);
2091e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (index < 0) {
2092e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            index = architectures.indexOf(arm64);
2093e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2094e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2095e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (index >= 0) {
2096e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf("native-code: '%s'\n", architectures[index].string());
2097e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            architectures.removeAt(index);
2098e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            outputAltNativeCode = true;
2099e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2100e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    }
2101e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2102e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    const size_t archCount = architectures.size();
2103e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    if (archCount > 0) {
2104e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (outputAltNativeCode) {
2105e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf("alt-");
2106e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2107e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        printf("native-code:");
2108e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        for (size_t i = 0; i < archCount; i++) {
2109e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf(" '%s'", architectures[i].string());
2110e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2111e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        printf("\n");
2112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                delete dir;
2115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badger", option) == 0) {
2117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s", CONSOLE_DATA);
2118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("configurations", option) == 0) {
2119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
2120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
2121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = configs.size();
2122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<N; i++) {
2123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("%s\n", configs[i].toString().string());
2124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
2127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
2132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (asset) {
2135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete asset;
2136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "add" command, which wants to add files to a new or
2143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * pre-existing archive.
2144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doAdd(Bundle* bundle)
2146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
2148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
2149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
2150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getUpdate()) {
2152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* avoid confusion */
2153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: can't use '-u' with add\n");
2154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
2158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
2159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
2162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
2164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
2165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, true);
2169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
2170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
2171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
2176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
2178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s'... (from gzip)\n", fileName);
2179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
2180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (bundle->getJunkPath()) {
2182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 storageName = String8(fileName).getPathLeaf();
21832675f769673f69b0661ddee346292f25cb30a296Maurice Chu                printf(" '%s' as '%s'...\n", fileName,
21842675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        ResTable::normalizeForOutput(storageName.string()).string());
2185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, storageName.string(),
2186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  bundle->getCompressionMethod(), NULL);
2187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
2188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'...\n", fileName);
2189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
2190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
2193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
2194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (result == NAME_NOT_FOUND) {
2195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": file not found\n");
2196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (result == ALREADY_EXISTS) {
2197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": already exists in archive\n");
2198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
2199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "\n");
2200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
2206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
2209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Delete files from an existing archive.
2215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doRemove(Bundle* bundle)
2217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
2219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
2220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
2221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
2223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
2224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
2227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
2229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
2230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, false);
2234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
2235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
2236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zipFileName);
2237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
2242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ZipEntry* entry;
2243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByName(fileName);
2245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (entry == NULL) {
2246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s' NOT FOUND\n", fileName);
2247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
2248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = zip->remove(entry);
2251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
2253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to delete '%s' from '%s'\n",
2254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                bundle->getFileSpecEntry(i), zipFileName);
2255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* update the archive */
2260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip->flush();
2261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
2264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
22673921e87e6e67a063caa1987937d7944b24aef489Adam Lesinskistatic status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
2268fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    const size_t numDirs = dir->getDirs().size();
2269fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    for (size_t i = 0; i < numDirs; i++) {
22703921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        bool ignore = ignoreConfig;
22713921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
22723921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        const char* dirStr = subDir->getLeaf().string();
22733921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
22743921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            ignore = true;
22753921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        }
22763921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        status_t err = addResourcesToBuilder(subDir, builder, ignore);
2277fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        if (err != NO_ERROR) {
2278fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            return err;
2279fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2280fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2281fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2282fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    const size_t numFiles = dir->getFiles().size();
2283fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    for (size_t i = 0; i < numFiles; i++) {
2284fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        sp<AaptGroup> gp = dir->getFiles().valueAt(i);
2285fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numConfigs = gp->getFiles().size();
2286fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t j = 0; j < numConfigs; j++) {
22873921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            status_t err = NO_ERROR;
22883921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            if (ignoreConfig) {
22893921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski                err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
22903921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            } else {
22913921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski                err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
22923921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            }
2293fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2294fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "Failed to add %s (%s) to builder.\n",
2295fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                        gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
2296fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                return err;
2297fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2298fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2299fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2300fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    return NO_ERROR;
2301fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski}
2302fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2303fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinskistatic String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
2304fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (split->isBase()) {
2305fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        return original;
2306fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2307fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2308fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    String8 ext(original.getPathExtension());
2309fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (ext == String8(".apk")) {
2310fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        return String8::format("%s_%s%s",
2311fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                original.getBasePath().string(),
2312fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                split->getDirectorySafeName().string(),
2313fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                ext.string());
2314fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2315fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2316fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    return String8::format("%s_%s", original.string(),
2317fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            split->getDirectorySafeName().string());
2318fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski}
2319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Package up an asset directory and associated application files.
2322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doPackage(Bundle* bundle)
2324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* outputAPKFile;
2326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int retVal = 1;
2327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err;
2328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<AaptAssets> assets;
2329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int N;
2330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    FILE* fp;
2331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 dependencyFile;
2332fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    sp<ApkBuilder> builder;
2333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2334a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin    // -c en_XA or/and ar_XB means do pseudolocalization
2335fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
2336fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    err = configFilter->parse(bundle->getConfigurations());
2337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
2338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2340fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (configFilter->containsPseudo()) {
2341a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
2342a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin    }
2343fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (configFilter->containsPseudoBidi()) {
2344a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
2345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    N = bundle->getFileSpecCount();
2348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
234909384303dea4f3f01d5682918d7bab9bf83a02b1Adam Lesinski            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
2350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no input files\n");
2351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    outputAPKFile = bundle->getOutputAPKFile();
2355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make sure the filenames provided exist and are of the appropriate type.
2357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
2358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        FileType type;
2359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        type = getFileType(outputAPKFile);
2360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
2361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr,
2362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                "ERROR: output file '%s' exists but is not regular file\n",
2363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                outputAPKFile);
2364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Load the assets.
2369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets = new AaptAssets();
2370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Set up the resource gathering in assets if we're going to generate
2372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // dependency files. Every time we encounter a resource while slurping
2373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the tree, we'll add it to these stores so we have full resource paths
2374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // to write to a dependency file.
2375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> resPathStore = new FilePathStore;
2377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullResPaths(resPathStore);
2378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> assetPathStore = new FilePathStore;
2379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullAssetPaths(assetPathStore);
2380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = assets->slurpFromArgs(bundle);
2383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
2384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
2388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->print(String8());
2389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2391fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // Create the ApkBuilder, which will collect the compiled files
2392fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // to write to the final APK (or sets of APKs if we are building
2393fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // a Split APK.
2394fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    builder = new ApkBuilder(configFilter);
2395fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2396fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // If we are generating a Split APK, find out which configurations to split on.
2397fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (bundle->getSplitConfigurations().size() > 0) {
2398fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
2399fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numSplits = splitStrs.size();
2400fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t i = 0; i < numSplits; i++) {
2401fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            std::set<ConfigDescription> configs;
2402fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
2403fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
2404fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2405fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2406fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2407fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            err = builder->createSplitForConfigs(configs);
2408fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2409fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2410fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2411fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2412fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2413fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If they asked for any fileAs that need to be compiled, do so.
2415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
2416fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        err = buildResources(bundle, assets, builder);
2417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != 0) {
2418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // At this point we've read everything and processed everything.  From here
2423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // on out it's just writing output files.
2424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Update symbols with information about which ones are needed as Java symbols.
2429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets->applyJavaSymbols();
2430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, do that here
2435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If this is the packaging step, generate the dependency file next to
2437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the output apk (e.g. bin/resources.ap_.d)
2438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outputAPKFile) {
2439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(outputAPKFile);
2440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Add the .d extension to the dependency file.
2441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.append(".d");
2442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Else if this is the R.java dependency generation step,
2444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // generate the dependency file in the R.java package subdirectory
2445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java.d
2446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(bundle->getRClassDir());
2447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.appendPath("R.java.d");
2448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Make sure we have a clean dependency file to start with
2450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "w");
2451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
2452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out R.java constants
2455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets->havePrivateSymbols()) {
2456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getCustomPackage() == NULL) {
2457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Write the R.java file into the appropriate class directory
2458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java
2459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = writeResourceSymbols(bundle, assets, assets->getPackage(), true);
2460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const String8 customPkg(bundle->getCustomPackage());
2462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = writeResourceSymbols(bundle, assets, customPkg, true);
2463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If we have library files, we're going to write our R.java file into
2468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the appropriate class directory for those libraries as well.
2469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // e.g. gen/com/foo/app/lib/R.java
2470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getExtraPackages() != NULL) {
2471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Split on colon
2472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 libs(bundle->getExtraPackages());
2473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
2474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while (packageString != NULL) {
2475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Write the R.java file out with the correct package name
2476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                err = writeResourceSymbols(bundle, assets, String8(packageString), true);
2477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (err < 0) {
2478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    goto bail;
2479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                packageString = strtok(NULL, ":");
2481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            libs.unlockBuffer();
2483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
2485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getPackage(), false);
2486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true);
2490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out the ProGuard file
2496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = writeProguardFile(bundle, assets);
2497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
2498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write the apk
2502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
2503fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        // Gather all resources and add them to the APK Builder. The builder will then
2504fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        // figure out which Split they belong in.
2505fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        err = addResourcesToBuilder(assets, builder);
2506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
2507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2509fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2510fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const Vector<sp<ApkSplit> >& splits = builder->getSplits();
2511fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numSplits = splits.size();
2512fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t i = 0; i < numSplits; i++) {
2513fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            const sp<ApkSplit>& split = splits[i];
2514fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            String8 outputPath = buildApkName(String8(outputAPKFile), split);
2515fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            err = writeAPK(bundle, outputPath, split);
2516fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2517fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
2518fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2519fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2520fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, we need to finish up here.
2524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the writeResourceSymbols and writeAPK functions have already written the target
2525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // half of the dependency file, now we need to write the prerequisites. (files that
2526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the R.java file or .ap_ file depend on)
2527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Now that writeResourceSymbols or writeAPK has taken care of writing
2529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the targets to our dependency file, we'll write the prereqs
2530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "a+");
2531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, " : ");
2532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool includeRaw = (outputAPKFile != NULL);
2533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
2534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Also manually add the AndroidManifeset since it's not under res/ or assets/
2535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // and therefore was not added to our pathstores during slurping
2536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
2537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
2538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    retVal = 0;
2541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        SourcePos::printErrors(stderr);
2544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return retVal;
2546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching
2550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * PRECONDITIONS
2551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -S flag points to a source directory containing drawable* folders
2552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -C flag points to destination directory. The folder structure in the
2553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *     source directory will be mirrored to the destination (cache) directory
2554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
2555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * POSTCONDITIONS
2556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  Destination directory will be updated to match the PNG files in
25572675f769673f69b0661ddee346292f25cb30a296Maurice Chu *  the source directory.
2558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doCrunch(Bundle* bundle)
2560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching PNG Files in ");
2562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
2563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
2564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    updatePreProcessedCache(bundle);
2566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching on a single flag
2572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -i points to a single png file
2573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -o points to a single png output file
2574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doSingleCrunch(Bundle* bundle)
2576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
2578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
2579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 input(bundle->getSingleCrunchInputFile());
2581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 output(bundle->getSingleCrunchOutputFile());
2582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
2584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // we can't return the status_t as it gets truncate to the lower 8 bits.
2585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 42;
2586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskichar CONSOLE_DATA[2925] = {
2592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
2597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
2598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
2601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
2602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
2605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
2608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
2609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
2612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
2613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
2616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
2619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
2620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
2623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
2626282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
2627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
2630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
2631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
2634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
2637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
2638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
2640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
2641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
2643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
2644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
2645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
2648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
2649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
2650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
2652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
2653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
2654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
2655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
2658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
2659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
2660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
2661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
2662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
2663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
2664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
2666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
2668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
2670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
2671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
2673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
2674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
2675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2677282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
2678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2679282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
2680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
2681282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2682282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
2684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
2685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2686282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2687282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
2691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
2692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
2696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
2699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
2702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
2703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
2709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
2710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
2713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
2714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
2717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
2718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
2719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
2720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
2721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
2724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
2725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
2726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
2727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
2728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
2735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
2738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
2739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
2742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
2743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
2745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
2746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
2749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
2750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10
2755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  };
2756