Command.cpp revision ad751224401564dcc8338df3d5c4c5de7722be8f
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
27ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski#ifndef AAPT_VERSION
28ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski    #define AAPT_VERSION ""
29ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski#endif
30ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Show version info.  All the cool kids do it.
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doVersion(Bundle* bundle)
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 0) {
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("(ignoring extra arguments)\n");
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
39ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski    printf("Android Asset Packaging Tool, v0.2-" AAPT_VERSION "\n");
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 0;
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read only.  The call fails if the file doesn't exist.
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadOnly(const char* fileName)
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip;
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, ZipFile::kOpenReadOnly);
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result == NAME_NOT_FOUND) {
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' not found\n", fileName);
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (result == PERMISSION_DENIED) {
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fileName);
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read-write.  The file will be created if it doesn't
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * already exist and "okayToCreate" is set.
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadWrite(const char* fileName, bool okayToCreate)
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int flags;
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    flags = ZipFile::kOpenReadWrite;
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (okayToCreate) {
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        flags |= ZipFile::kOpenCreate;
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, flags);
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        zip = NULL;
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return a short string describing the compression method.
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiconst char* compressionName(int method)
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (method == ZipEntry::kCompressStored) {
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Stored";
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (method == ZipEntry::kCompressDeflated) {
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Deflated";
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Unknown";
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return the percent reduction in size (0% == no compression).
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint calcPercent(long uncompressedLen, long compressedLen)
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!uncompressedLen) {
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 0;
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "list" command, which can be a simple file dump or
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * a verbose listing.
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The verbose listing closely matches the output of the Info-ZIP "unzip"
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * command.
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doList(Bundle* bundle)
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int result = 1;
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ZipEntry* entry;
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    long totalUncLen, totalCompLen;
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 1) {
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: specify zip file name (only)\n");
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadOnly(zipFileName);
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int count, i;
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("Archive:  %s\n", zipFileName);
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            " Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name\n");
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            "--------  ------  ------- -----  -------      ----  ----  ------    ----\n");
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    totalUncLen = totalCompLen = 0;
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    count = zip->getNumEntries();
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i = 0; i < count; i++) {
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByIndex(i);
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getVerbose()) {
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char dateBuf[32];
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            time_t when;
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            when = entry->getModWhen();
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                localtime(&when));
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%8ld  %-7.7s %7ld %3d%%  %8zd  %s  %08lx  %s\n",
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getUncompressedLen(),
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                compressionName(entry->getCompressionMethod()),
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getCompressedLen(),
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                calcPercent(entry->getUncompressedLen(),
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            entry->getCompressedLen()),
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (size_t) entry->getLFHOffset(),
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                dateBuf,
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getCRC32(),
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getFileName());
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s\n", entry->getFileName());
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalUncLen += entry->getUncompressedLen();
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalCompLen += entry->getCompressedLen();
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "--------          -------  ---                            -------\n");
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("%8ld          %7ld  %2d%%                            %d files\n",
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalUncLen,
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalCompLen,
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            calcPercent(totalUncLen, totalCompLen),
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zip->getNumEntries());
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getAndroidList()) {
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        AssetManager assets;
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!assets.addAssetPath(String8(zipFileName), NULL)) {
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResTable& res = assets.getResources(false);
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (&res == NULL) {
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo resource table found.\n");
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nResource table:\n");
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.print(false);
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                   Asset::ACCESS_BUFFER);
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (manifestAsset == NULL) {
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo AndroidManifest.xml found.\n");
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nAndroid manifest:\n");
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree tree;
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.setTo(manifestAsset->getBuffer(true),
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       manifestAsset->getLength());
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete manifestAsset;
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = 0;
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes)
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t N = tree.getAttributeCount();
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.getAttributeNameResID(i) == attrRes) {
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return (ssize_t)i;
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return -1;
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiString8 getAttribute(const ResXMLTree& tree, const char* ns,
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char* attr, String8* outError)
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = tree.indexOfAttribute(ns, attr);
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError)
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes,
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String8* outError, int32_t defValue = -1)
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return defValue;
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType < Res_value::TYPE_FIRST_INT
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || value.dataType > Res_value::TYPE_LAST_INT) {
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not an integer value";
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return defValue;
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return value.data;
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree,
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t attrRes, String8* outError, int32_t defValue = -1)
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return defValue;
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType == Res_value::TYPE_REFERENCE) {
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            resTable->resolveReference(&value, 0);
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType < Res_value::TYPE_FIRST_INT
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || value.dataType > Res_value::TYPE_LAST_INT) {
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not an integer value";
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return defValue;
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return value.data;
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree,
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t attrRes, String8* outError)
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType == Res_value::TYPE_STRING) {
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const uint16_t* str = tree.getAttributeStringValue(idx, &len);
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return str ? String8(str, len) : String8();
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        resTable->resolveReference(&value, 0);
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const Res_value* value2 = &value;
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len);
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic void getResolvedResourceAttribute(Res_value* value, const ResTable* resTable,
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResXMLTree& tree, uint32_t attrRes, String8* outError)
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outError != NULL) {
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            *outError = "attribute could not be found";
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, value) != NO_ERROR) {
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value->dataType == Res_value::TYPE_REFERENCE) {
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            resTable->resolveReference(value, 0);
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // The attribute was found and was resolved if need be.
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outError != NULL) {
385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *outError = "error getting resolved resource attribute";
386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
38976327314d2238e105f8b94909f9c0cf85caca318Maurice Chustatic void printResolvedResourceAttribute(const ResTable* resTable, const ResXMLTree& tree,
39076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        uint32_t attrRes, String8 attrLabel, String8* outError)
39176327314d2238e105f8b94909f9c0cf85caca318Maurice Chu{
39276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    Res_value value;
39376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    getResolvedResourceAttribute(&value, resTable, tree, attrRes, outError);
39476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (*outError != "") {
39576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        *outError = "error print resolved resource attribute";
39676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        return;
39776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
39876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (value.dataType == Res_value::TYPE_STRING) {
39976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        String8 result = getResolvedAttribute(resTable, tree, attrRes, outError);
4002675f769673f69b0661ddee346292f25cb30a296Maurice Chu        printf("%s='%s'", attrLabel.string(),
4012675f769673f69b0661ddee346292f25cb30a296Maurice Chu                ResTable::normalizeForOutput(result.string()).string());
40276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
40376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu            value.dataType <= Res_value::TYPE_LAST_INT) {
40476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='%d'", attrLabel.string(), value.data);
40576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else {
40676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='0x%x'", attrLabel.string(), (int)value.data);
40776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
40876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu}
40976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu
410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// These are attribute resource constants for the platform, as found
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// in android.R.attr
412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskienum {
413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LABEL_ATTR = 0x01010001,
414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ICON_ATTR = 0x01010002,
415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NAME_ATTR = 0x01010003,
416a5018c900f126ee8424c82497f32983873db741bAdam Lesinski    PERMISSION_ATTR = 0x01010006,
4179d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    EXPORTED_ATTR = 0x01010010,
4189d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
41994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    RESOURCE_ATTR = 0x01010025,
420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    DEBUGGABLE_ATTR = 0x0101000f,
421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VALUE_ATTR = 0x01010024,
422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_CODE_ATTR = 0x0101021b,
423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_NAME_ATTR = 0x0101021c,
424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_ORIENTATION_ATTR = 0x0101001e,
425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MIN_SDK_VERSION_ATTR = 0x0101020c,
426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MAX_SDK_VERSION_ATTR = 0x01010271,
427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_TOUCH_SCREEN_ATTR = 0x01010227,
428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_HARD_KEYBOARD_ATTR = 0x01010229,
430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_NAVIGATION_ATTR = 0x0101022a,
431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TARGET_SDK_VERSION_ATTR = 0x01010270,
433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TEST_ONLY_ATTR = 0x01010272,
434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ANY_DENSITY_ATTR = 0x0101026c,
435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    GL_ES_VERSION_ATTR = 0x01010281,
436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SMALL_SCREEN_ATTR = 0x01010284,
437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NORMAL_SCREEN_ATTR = 0x01010285,
438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGE_SCREEN_ATTR = 0x01010286,
439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    XLARGE_SCREEN_ATTR = 0x010102bf,
440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRED_ATTR = 0x0101028e,
441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_SIZE_ATTR = 0x010102ca,
442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_DENSITY_ATTR = 0x010102cb,
443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    PUBLIC_KEY_ATTR = 0x010103a6,
44794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    CATEGORY_ATTR = 0x010103e8,
4480a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn    BANNER_ATTR = 0x10103f2,
449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4512675f769673f69b0661ddee346292f25cb30a296Maurice ChuString8 getComponentName(String8 &pkgName, String8 &componentName) {
452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = componentName.find(".");
453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 retStr(pkgName);
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx == 0) {
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (idx < 0) {
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += ".";
458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
4602675f769673f69b0661ddee346292f25cb30a296Maurice Chu        return componentName;
461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4622675f769673f69b0661ddee346292f25cb30a296Maurice Chu    return retStr;
463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4659cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinskistatic void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResXMLTree::event_code_t code;
468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int depth = 0;
469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool first = true;
470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("compatible-screens:");
471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code == ResXMLTree::END_TAG) {
473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            depth--;
474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (depth < 0) {
475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code != ResXMLTree::START_TAG) {
480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        depth++;
4839cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        const char16_t* ctag16 = tree.getElementName(&len);
4849cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        if (ctag16 == NULL) {
4859cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            *outError = "failed to get XML element name (bad string pool)";
4869cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            return;
4879cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        }
4889cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        String8 tag(ctag16);
489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tag == "screen") {
490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int32_t screenSize = getIntegerAttribute(tree,
491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SCREEN_SIZE_ATTR, NULL, -1);
492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int32_t screenDensity = getIntegerAttribute(tree,
493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SCREEN_DENSITY_ATTR, NULL, -1);
494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (screenSize > 0 && screenDensity > 0) {
495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!first) {
496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf(",");
497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                first = false;
499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("'%d/%d'", screenSize, screenDensity);
500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("\n");
504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
50658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
50758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
50858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (maxSdkVersion != -1) {
50958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski         printf(" maxSdkVersion='%d'", maxSdkVersion);
51058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
51158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("\n");
51258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
51358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (optional) {
51458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("optional-permission: name='%s'",
51558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                ResTable::normalizeForOutput(name.string()).string());
51658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        if (maxSdkVersion != -1) {
51758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            printf(" maxSdkVersion='%d'", maxSdkVersion);
51858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        }
51958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("\n");
52058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
52158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
52258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
52358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesImpliedPermission(const String8& name, const String8& reason) {
52458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-implied-permission: name='%s' reason='%s'\n",
52558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(name.string()).string(),
52658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(reason.string()).string());
52758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
52858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
52994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam LesinskiVector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost,
53094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        String8 *outError = NULL)
53194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski{
53294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
53394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    if (aidAsset == NULL) {
53494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (outError != NULL) *outError = "xml resource does not exist";
53594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        return Vector<String8>();
53694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
53794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
53894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
53994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
54094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    bool withinApduService = false;
54194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Vector<String8> categories;
54294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
54394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    String8 error;
54494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree tree;
54594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
54694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
54794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    size_t len;
54894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    int depth = 0;
54994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree::event_code_t code;
55094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
55194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (code == ResXMLTree::END_TAG) {
55294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth--;
5539cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
5549cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
5559cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
5569cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
5579cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
5589cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
55994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
56094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 0 && tag == serviceTagName) {
56194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                withinApduService = false;
56294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
56394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
56494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        } else if (code == ResXMLTree::START_TAG) {
56594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth++;
5669cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
5679cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
5689cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
5699cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
5709cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
5719cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
57294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
57394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 1) {
57494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == serviceTagName) {
57594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    withinApduService = true;
57694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
57794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            } else if (depth == 2 && withinApduService) {
57894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == "aid-group") {
57994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    String8 category = getAttribute(tree, CATEGORY_ATTR, &error);
58094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (error != "") {
58194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (outError != NULL) *outError = error;
58294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        return Vector<String8>();
58394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
58494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
58594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    categories.add(category);
58694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
58794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
58894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        }
58994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
59094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    aidAsset->close();
59194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    return categories;
59294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski}
59394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
5949d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinskistatic void printComponentPresence(const char* componentName) {
5959d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    printf("provides-component:'%s'\n", componentName);
5969d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski}
5979d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
5982c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
5992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a feature that has been automatically added due to
6002c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * a pre-requisite or some other reason.
6012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
6022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct ImpliedFeature {
6032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6042c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Name of the implied feature.
6052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name;
6072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6082c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6092c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * List of human-readable reasons for why this feature was implied.
6102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    SortedVector<String8> reasons;
6122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
6132c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6142c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
6152c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a <feature-group> tag in the AndroidManifest.xml
6162c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
6172c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct FeatureGroup {
618d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    FeatureGroup() : openGLESVersion(-1) {}
619d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
6202c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Human readable label
6222c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6232c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 label;
6242c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6252c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6262c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Explicit features defined in the group
6272c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6282c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    KeyedVector<String8, bool> features;
629d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
630d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    /**
631d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     * OpenGL ES version required
632d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     */
633d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    int openGLESVersion;
6342c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
6352c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6362c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
6372c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const char* name, const char* reason) {
6382c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name8(name);
6392c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    ssize_t idx = impliedFeatures->indexOfKey(name8);
6402c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (idx < 0) {
6412c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        idx = impliedFeatures->add(name8, ImpliedFeature());
6422c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        impliedFeatures->editValueAt(idx).name = name8;
6432c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6442c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    impliedFeatures->editValueAt(idx).reasons.add(String8(reason));
6452c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
6462c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6472c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void printFeatureGroup(const FeatureGroup& grp,
6482c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const KeyedVector<String8, ImpliedFeature>* impliedFeatures = NULL) {
6492c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    printf("feature-group: label='%s'\n", grp.label.string());
6502c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
651d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    if (grp.openGLESVersion > 0) {
652d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        printf("  uses-gl-es: '0x%x'\n", grp.openGLESVersion);
653d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    }
654d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
6552c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numFeatures = grp.features.size();
6562c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numFeatures; i++) {
6572c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        if (!grp.features[i]) {
6582c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            continue;
6592c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6602c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6612c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const String8& featureName = grp.features.keyAt(i);
6622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("  uses-feature: name='%s'\n",
6632c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                ResTable::normalizeForOutput(featureName.string()).string());
6642c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6652c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6662c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numImpliedFeatures =
6672c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        (impliedFeatures != NULL) ? impliedFeatures->size() : 0;
6682c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numImpliedFeatures; i++) {
6692c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i);
6702c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        if (grp.features.indexOfKey(impliedFeature.name) >= 0) {
6712c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // The feature is explicitly set, no need to use implied
6722c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // definition.
6732c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            continue;
6742c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6752c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6762c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        String8 printableFeatureName(ResTable::normalizeForOutput(
6772c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    impliedFeature.name.string()));
6782c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("  uses-feature: name='%s'\n", printableFeatureName.string());
6792c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("  uses-implied-feature: name='%s' reason='",
6802c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printableFeatureName.string());
6812c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const size_t numReasons = impliedFeature.reasons.size();
6822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        for (size_t j = 0; j < numReasons; j++) {
6832c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            printf("%s", impliedFeature.reasons[j].string());
6842c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            if (j + 2 < numReasons) {
6852c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", ");
6862c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            } else if (j + 1 < numReasons) {
6872c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", and ");
6882c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            }
6892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("'\n");
6912c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6922c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
6932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addParentFeatures(FeatureGroup* grp, const String8& name) {
6952c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (name == "android.hardware.camera.autofocus" ||
6962c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.camera.flash") {
6972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.camera"), true);
6982c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.location.gps" ||
6992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.location.network") {
7002c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.location"), true);
7012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch") {
7022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), true);
7032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
7042c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen.multitouch"), true);
7052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), true);
706d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    } else if (name == "android.hardware.opengles.aep") {
707d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        const int openGLESVersion31 = 0x00030001;
708d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        if (openGLESVersion31 > grp->openGLESVersion) {
709d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski            grp->openGLESVersion = openGLESVersion31;
710d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        }
7112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
7122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
7132c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "dump" command, to extract select data from an archive.
716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiextern char CONSOLE_DATA[2925]; // see EOF
718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doDump(Bundle* bundle)
719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump option specified\n");
724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump file specified\n");
729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* option = bundle->getFileSpecEntry(0);
733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* filename = bundle->getFileSpecEntry(1);
734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    AssetManager assets;
736f85e41f29a0e9313c2d4725f9d9648591ea49f3bNarayan Kamath    int32_t assetsCookie;
737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make a dummy config for retrieving resources...  we need to supply
743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // non-default values for some configs so that we can retrieve resources
744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // in the app that don't have a default.  The most important of these is
745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the API version because key resources like icons will have an implicit
746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // version if they are using newer config types like density.
747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_config config;
74891447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath    memset(&config, 0, sizeof(ResTable_config));
749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[0] = 'e';
750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[1] = 'n';
751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[0] = 'U';
752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[1] = 'S';
753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.orientation = ResTable_config::ORIENTATION_PORT;
754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.density = ResTable_config::DENSITY_MEDIUM;
755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.sdkVersion = 10000; // Very high.
756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenWidthDp = 320;
757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenHeightDp = 480;
758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.smallestScreenWidthDp = 320;
759c2dea8daea2ae0001d56689d96ce1066012b7b40Adam Lesinski    config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL;
760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets.setConfiguration(config);
761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ResTable& res = assets.getResources(false);
763282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (&res == NULL) {
764282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
76563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        return 1;
76625e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski    } else if (res.getError() != NO_ERROR) {
76725e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
76863e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        return 1;
76963e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    }
77063e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski
7712cb761e3ddb9d68ab430013e9cd15ecaab9fbc62Adam Lesinski    // The dynamicRefTable can be null if there are no resources for this asset cookie.
7722cb761e3ddb9d68ab430013e9cd15ecaab9fbc62Adam Lesinski    // This fine.
77363e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie);
774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
77563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    Asset* asset = NULL;
77663e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski
777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strcmp("resources", option) == 0) {
778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        res.print(bundle->getValues());
780282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("strings", option) == 0) {
783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResStringPool* pool = res.getTableStringBlock(0);
784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printStringPool(pool);
785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmltree", option) == 0) {
787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
791282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
79463e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            ResXMLTree tree(dynamicRefTable);
79563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
804282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.restart();
807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.uninit();
809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmlstrings", option) == 0) {
814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
82163e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
826282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
82763e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            ResXMLTree tree(dynamicRefTable);
828282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printStringPool(&tree.getStrings());
834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
83963e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER);
840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (asset == NULL) {
841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
84563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        ResXMLTree tree(dynamicRefTable);
846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.setTo(asset->getBuffer(true),
847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       asset->getLength()) != NO_ERROR) {
848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        tree.restart();
852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcmp("permissions", option) == 0) {
854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
8669cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                const char16_t* ctag16 = tree.getElementName(&len);
8679cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                if (ctag16 == NULL) {
8689cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
8699cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    goto bail;
8709cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                }
8719cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                String8 tag(ctag16);
872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d tag %s\n", depth, tag.string());
873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 pkg = getAttribute(tree, NULL, "package", NULL);
8792675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "permission") {
881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 name = getAttribute(tree, NAME_ATTR, &error);
883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
8872675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("permission: %s\n",
8882675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(name.string()).string());
889282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "uses-permission") {
890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 name = getAttribute(tree, NAME_ATTR, &error);
892282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
893282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
894282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
895282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
89658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(name,
89758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
89858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
899282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
901282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badging", option) == 0) {
902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<String8> locales;
903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getLocales(&locales);
904282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
905282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
906282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            SortedVector<int> densities;
908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NC = configs.size();
909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NC; i++) {
910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int dens = configs[i].density;
911282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dens == 0) {
912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    dens = 160;
913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                densities.add(dens);
915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 error;
921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinActivity = false;
922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isMainActivity = false;
923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isLauncherActivity = false;
9240a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            bool isLeanbackLauncherActivity = false;
925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isSearchable = false;
926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinApplication = false;
927ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            bool withinSupportsInput = false;
9282c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            bool withinFeatureGroup = false;
929282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinReceiver = false;
930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinService = false;
9319d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool withinProvider = false;
932282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinIntentFilter = false;
933282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasMainActivity = false;
934282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherActivities = false;
935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherReceivers = false;
936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherServices = false;
9379d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasIntentFilter = false;
9389d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWallpaperService = false;
940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasImeService = false;
941a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasAccessibilityService = false;
942a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasPrintService = false;
943282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWidgetReceivers = false;
944a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasDeviceAdminReceiver = false;
94594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasPaymentService = false;
9469d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasDocumentsProvider = false;
9479d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasCameraActivity = false;
9489d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasCameraSecureActivity = false;
9499d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasLauncher = false;
9509d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasNotificationListenerService = false;
951eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool hasDreamService = false;
9529d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
953282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actMainActivity = false;
954282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWidgetReceivers = false;
955a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actDeviceAdminEnabled = false;
956282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actImeService = false;
957282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWallpaperService = false;
958a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actAccessibilityService = false;
959a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actPrintService = false;
96094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actHostApduService = false;
96194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actOffHostApduService = false;
9629d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actDocumentsProvider = false;
9639d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actNotificationListenerService = false;
964eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool actDreamService = false;
9659d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actCamera = false;
9669d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actCameraSecure = false;
9679d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool catLauncher = false;
96894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaHostPaymentCategory = false;
96994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaOffHostPaymentCategory = false;
970a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
971a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // These permissions are required by services implementing services
972a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // the system binds to (IME, Accessibility, PrintServices, etc.)
973a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindDeviceAdminPermission = false;
974a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindInputMethodPermission = false;
975a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindAccessibilityServicePermission = false;
976a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindPrintServicePermission = false;
97794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasBindNfcServicePermission = false;
9789d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasRequiredSafAttributes = false;
9799d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasBindNotificationListenerServicePermission = false;
980eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool hasBindDreamServicePermission = false;
981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // These two implement the implicit permissions that are granted
983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // to pre-1.6 applications.
984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteExternalStoragePermission = false;
985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadPhoneStatePermission = false;
986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If an app requests write storage, they will also get read storage.
988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadExternalStoragePermission = false;
989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Implement transition to read and write call log.
991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadContactsPermission = false;
992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteContactsPermission = false;
993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadCallLogPermission = false;
994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteCallLogPermission = false;
995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
996e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            // If an app declares itself as multiArch, we report the
997e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            // native libraries differently.
998e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            bool hasMultiArch = false;
999e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
1000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This next group of variables is used to implement a group of
1001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // backward-compatibility heuristics necessitated by the addition of
1002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // some new uses-feature constants in 2.1 and 2.2. In most cases, the
1003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // heuristic is "if an app requests a permission but doesn't explicitly
1004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // request the corresponding <uses-feature>, presume it's there anyway".
10052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // 2.2 also added some other features that apps can request, but that
1007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // have no corresponding permission, so we cannot implement any
1008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // back-compatibility heuristic for them. The below are thus unnecessary
1009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // (but are retained here for documentary purposes.)
1010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specCompassFeature = false;
1011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAccelerometerFeature = false;
1012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specProximityFeature = false;
1013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAmbientLightFeature = false;
1014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specLiveWallpaperFeature = false;
1015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int targetSdk = 0;
1017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int smallScreen = 1;
1018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int normalScreen = 1;
1019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largeScreen = 1;
1020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int xlargeScreen = 1;
1021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int anyDensity = 1;
1022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int requiresSmallestWidthDp = 0;
1023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int compatibleWidthLimitDp = 0;
1024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largestWidthLimitDp = 0;
1025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 pkg;
1026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityName;
1027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityLabel;
1028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityIcon;
10290a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            String8 activityBanner;
1030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 receiverName;
1031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 serviceName;
1032ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            Vector<String8> supportedInput;
10332c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
10342c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            FeatureGroup commonFeatures;
10352c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            Vector<FeatureGroup> featureGroups;
10362c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            KeyedVector<String8, ImpliedFeature> impliedFeatures;
10372c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
1040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
1041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (depth < 2) {
1042ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if (withinSupportsInput && !supportedInput.isEmpty()) {
1043ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("supports-input: '");
1044ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            const size_t N = supportedInput.size();
1045ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            for (size_t i=0; i<N; i++) {
10462675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                printf("%s", ResTable::normalizeForOutput(
10472675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        supportedInput[i].string()).string());
1048ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (i != N - 1) {
1049ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("' '");
1050ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else {
1051ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("'\n");
1052ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1053ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1054ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            supportedInput.clear();
1055ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        }
1056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = false;
1057ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = false;
10582c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        withinFeatureGroup = false;
1059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 3) {
10600a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                        if (withinActivity && isMainActivity) {
10612675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            String8 aName(getComponentName(pkg, activityName));
10620a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (isLauncherActivity) {
10630a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf("launchable-activity:");
10649eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                if (aName.length() > 0) {
10659eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                    printf(" name='%s' ",
10669eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                            ResTable::normalizeForOutput(aName.string()).string());
10670a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                }
10680a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf(" label='%s' icon='%s'\n",
10699eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
10709eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityIcon.string()).string());
10710a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            }
10720a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (isLeanbackLauncherActivity) {
10730a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf("leanback-launchable-activity:");
10749eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                if (aName.length() > 0) {
10759eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                    printf(" name='%s' ",
10769eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                            ResTable::normalizeForOutput(aName.string()).string());
10770a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                }
10780a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf(" label='%s' icon='%s' banner='%s'\n",
10799eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
10809eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityIcon.string()).string(),
10819eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityBanner.string()).string());
1082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1084282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (!hasIntentFilter) {
1085282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherActivities |= withinActivity;
1086282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherReceivers |= withinReceiver;
1087282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherServices |= withinService;
108894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        } else {
108994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (withinService) {
109094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
109194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        hasBindNfcServicePermission);
109294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
109394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        hasBindNfcServicePermission);
109494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
1095282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinActivity = false;
1097282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinService = false;
1098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinReceiver = false;
10999d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        withinProvider = false;
1100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasIntentFilter = false;
11010a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                        isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false;
1102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 4) {
1103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (withinIntentFilter) {
1104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (withinActivity) {
1105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasMainActivity |= actMainActivity;
11069d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasLauncher |= catLauncher;
11079d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasCameraActivity |= actCamera;
11089d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasCameraSecureActivity |= actCameraSecure;
11099d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasOtherActivities |= !actMainActivity && !actCamera && !actCameraSecure;
1110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinReceiver) {
1111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWidgetReceivers |= actWidgetReceivers;
1112a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
1113a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindDeviceAdminPermission);
1114a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled);
1115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinService) {
1116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasImeService |= actImeService;
1117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWallpaperService |= actWallpaperService;
1118a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasAccessibilityService |= (actAccessibilityService &&
1119a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindAccessibilityServicePermission);
1120a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasPrintService |= (actPrintService && hasBindPrintServicePermission);
11219d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasNotificationListenerService |= actNotificationListenerService &&
11229d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        hasBindNotificationListenerServicePermission;
1123eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                hasDreamService |= actDreamService && hasBindDreamServicePermission;
1124a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasOtherServices |= (!actImeService && !actWallpaperService &&
112594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        !actAccessibilityService && !actPrintService &&
11269d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        !actHostApduService && !actOffHostApduService &&
11279d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        !actNotificationListenerService);
11289d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (withinProvider) {
11299d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasDocumentsProvider |= actDocumentsProvider && hasRequiredSafAttributes;
1130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinIntentFilter = false;
1133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
1135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
1137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
1138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
11409cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski
11419cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                const char16_t* ctag16 = tree.getElementName(&len);
11429cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                if (ctag16 == NULL) {
11439cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
11449cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    goto bail;
11459cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                }
11469cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                String8 tag(ctag16);
1147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d,  %s\n", depth, tag.string());
1148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
1149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
1150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
1151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    pkg = getAttribute(tree, NULL, "package", NULL);
11542675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("package: name='%s' ",
11552675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(pkg.string()).string());
1156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error);
1157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
1158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string());
1159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (versionCode > 0) {
1162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='%d' ", versionCode);
1163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
1164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='' ");
1165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error);
1167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
1168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string());
1169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
117125d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    printf("versionName='%s'",
11722675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(versionName.string()).string());
117325d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski
117425d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    String8 splitName = getAttribute(tree, NULL, "split", NULL);
117525d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    if (!splitName.isEmpty()) {
117625d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                        printf(" split='%s'", ResTable::normalizeForOutput(
117725d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                                    splitName.string()).string());
117825d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    }
117925d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    printf("\n");
1180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2) {
1181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinApplication = false;
1182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag == "application") {
1183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = true;
1184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 label;
1186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t NL = locales.size();
1187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<NL; i++) {
1188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char* localeStr =  locales[i].string();
1189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setLocale(localeStr != NULL ? localeStr : "");
1190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (llabel != "") {
1192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                if (localeStr == NULL || strlen(localeStr) == 0) {
1193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    label = llabel;
11942675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    printf("application-label:'%s'\n",
11952675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                            ResTable::normalizeForOutput(llabel.string()).string());
1196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                } else {
1197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    if (label == "") {
1198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        label = llabel;
1199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    }
1200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    printf("application-label-%s:'%s'\n", localeStr,
12012675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                           ResTable::normalizeForOutput(llabel.string()).string());
1202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResTable_config tmpConfig = config;
1207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t ND = densities.size();
1208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<ND; i++) {
1209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            tmpConfig.density = densities[i];
1210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setConfiguration(tmpConfig);
1211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (icon != "") {
12132675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                printf("application-icon-%d:'%s'\n", densities[i],
12142675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(icon.string()).string());
1215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        assets.setConfiguration(config);
1218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
1222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
1225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
1227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
12292675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        printf("application: label='%s' ",
12302675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                ResTable::normalizeForOutput(label.string()).string());
12312675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        printf("icon='%s'\n", ResTable::normalizeForOutput(icon.string()).string());
1232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (testOnly != 0) {
1233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("testOnly='%d'\n", testOnly);
1234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0);
1237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string());
1239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (debuggable != 0) {
1242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("application-debuggable\n");
1243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1244e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
1245e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // We must search by name because the multiArch flag hasn't been API
1246e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // frozen yet.
1247e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        int32_t multiArchIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
1248e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                "multiArch");
1249e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (multiArchIndex >= 0) {
1250e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            Res_value value;
1251e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            if (tree.getAttributeValue(multiArchIndex, &value) != NO_ERROR) {
1252e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                if (value.dataType >= Res_value::TYPE_FIRST_INT &&
1253e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                        value.dataType <= Res_value::TYPE_LAST_INT) {
1254e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                    hasMultiArch = value.data;
1255e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                }
1256e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            }
1257e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
1258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-sdk") {
1259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
1260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
1262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
1263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
1264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
1265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
1266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut") targetSdk = 4;
12692675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("sdkVersion:'%s'\n",
12702675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
1272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            targetSdk = code;
1273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("sdkVersion:'%d'\n", code);
1274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1);
1276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (code != -1) {
1277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("maxSdkVersion:'%d'\n", code);
1278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
1280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
1282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
1283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
1284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
1285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
1286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
12892675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("targetSdkVersion:'%s'\n",
12902675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
1292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (targetSdk < code) {
1293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                targetSdk = code;
1294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("targetSdkVersion:'%d'\n", code);
1296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-configuration") {
1298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqTouchScreen = getIntegerAttribute(tree,
1299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_TOUCH_SCREEN_ATTR, NULL, 0);
1300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqKeyboardType = getIntegerAttribute(tree,
1301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
1302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqHardKeyboard = getIntegerAttribute(tree,
1303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_HARD_KEYBOARD_ATTR, NULL, 0);
1304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqNavigation = getIntegerAttribute(tree,
1305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_NAVIGATION_ATTR, NULL, 0);
1306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqFiveWayNav = getIntegerAttribute(tree,
1307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
1308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("uses-configuration:");
1309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqTouchScreen != 0) {
1310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqTouchScreen='%d'", reqTouchScreen);
1311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqKeyboardType != 0) {
1313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqKeyboardType='%d'", reqKeyboardType);
1314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqHardKeyboard != 0) {
1316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqHardKeyboard='%d'", reqHardKeyboard);
1317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqNavigation != 0) {
1319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqNavigation='%d'", reqNavigation);
1320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqFiveWayNav != 0) {
1322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqFiveWayNav='%d'", reqFiveWayNav);
1323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("\n");
1325ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    } else if (tag == "supports-input") {
1326ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = true;
1327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-screens") {
1328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        smallScreen = getIntegerAttribute(tree,
1329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                SMALL_SCREEN_ATTR, NULL, 1);
1330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        normalScreen = getIntegerAttribute(tree,
1331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                NORMAL_SCREEN_ATTR, NULL, 1);
1332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        largeScreen = getIntegerAttribute(tree,
1333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                LARGE_SCREEN_ATTR, NULL, 1);
1334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        xlargeScreen = getIntegerAttribute(tree,
1335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                XLARGE_SCREEN_ATTR, NULL, 1);
1336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        anyDensity = getIntegerAttribute(tree,
1337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                ANY_DENSITY_ATTR, NULL, 1);
1338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        requiresSmallestWidthDp = getIntegerAttribute(tree,
1339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0);
1340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        compatibleWidthLimitDp = getIntegerAttribute(tree,
1341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0);
1342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        largestWidthLimitDp = getIntegerAttribute(tree,
1343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0);
13442c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    } else if (tag == "feature-group") {
13452c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        withinFeatureGroup = true;
13462c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        FeatureGroup group;
13472c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        group.label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
13482c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        if (error != "") {
13492c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:label' attribute:"
13502c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    " %s\n", error.string());
13512c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            goto bail;
13522c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
13532c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        featureGroups.add(group);
13542c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-feature") {
1356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            int req = getIntegerAttribute(tree,
1359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    REQUIRED_ATTR, NULL, 1);
1360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
13612c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            commonFeatures.features.add(name, req);
13622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            if (req) {
13632c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addParentFeatures(&commonFeatures, name);
1364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            int vers = getIntegerAttribute(tree,
1367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    GL_ES_VERSION_ATTR, &error);
1368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error == "") {
1369d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                if (vers > commonFeatures.openGLESVersion) {
1370d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    commonFeatures.openGLESVersion = vers;
1371d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                }
1372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-permission") {
1375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "android.permission.CAMERA") {
1378d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.camera",
13792c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13802c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
13822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location.gps",
13832c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13842c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
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_MOCK_LOCATION") {
13892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
13902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13912c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
13932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location.network",
13942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13952c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
13962c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
13972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
13982c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
1400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.INSTALL_LOCATION_PROVIDER") {
14012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
14022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.BLUETOOTH" ||
1405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.BLUETOOTH_ADMIN") {
14062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                if (targetSdk > 4) {
14072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
14082c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            String8::format("requested %s permission", name.string())
14092c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            .string());
14102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
14112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            "targetSdkVersion > 4");
14122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                }
1413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.RECORD_AUDIO") {
14142c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.microphone",
14152c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14162c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
1418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CHANGE_WIFI_STATE" ||
1419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
14202c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.wifi",
14212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14222c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.CALL_PHONE" ||
1424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CALL_PRIVILEGED" ||
1425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.MODIFY_PHONE_STATE" ||
1426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.PROCESS_OUTGOING_CALLS" ||
1427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.READ_SMS" ||
1428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_SMS" ||
1429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_MMS" ||
1430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_WAP_PUSH" ||
1431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.SEND_SMS" ||
1432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.WRITE_APN_SETTINGS" ||
1433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.WRITE_SMS") {
14342c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.telephony",
14352c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8("requested a telephony permission").string());
1436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
1437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteExternalStoragePermission = true;
1438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
1439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadExternalStoragePermission = true;
1440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_PHONE_STATE") {
1441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadPhoneStatePermission = true;
1442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_CONTACTS") {
1443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadContactsPermission = true;
1444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_CONTACTS") {
1445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteContactsPermission = true;
1446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_CALL_LOG") {
1447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadCallLogPermission = true;
1448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_CALL_LOG") {
1449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteCallLogPermission = true;
1450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
145158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
145258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            printUsesPermission(name,
145358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                                    getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
145458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                                    getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
145558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                       } else {
1456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-package") {
1461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
14632675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("uses-package:'%s'\n",
14642675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "original-package") {
1471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
14732675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("original-package:'%s'\n",
14742675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-gl-texture") {
1481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
14832675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("supports-gl-texture:'%s'\n",
14842675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "compatible-screens") {
14919cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        printCompatibleScreens(tree, &error);
14929cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        if (error != "") {
14939cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                            fprintf(stderr, "ERROR getting compatible screens: %s\n",
14949cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                                    error.string());
14959cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                            goto bail;
14969cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        }
1497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        depth--;
1498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "package-verifier") {
1499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error);
1502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (publicKey != "" && error == "") {
1503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                printf("package-verifier: name='%s' publicKey='%s'\n",
15042675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(name.string()).string(),
15052675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(publicKey.string()).string());
1506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1509ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                } else if (depth == 3) {
1510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinActivity = false;
1511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinReceiver = false;
1512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinService = false;
15139d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    withinProvider = false;
1514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasIntentFilter = false;
151594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasMetaHostPaymentCategory = false;
151694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasMetaOffHostPaymentCategory = false;
151794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindDeviceAdminPermission = false;
151894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindInputMethodPermission = false;
151994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindAccessibilityServicePermission = false;
152094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindPrintServicePermission = false;
152194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindNfcServicePermission = false;
15229d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    hasRequiredSafAttributes = false;
15239d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    hasBindNotificationListenerServicePermission = false;
1524eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                    hasBindDreamServicePermission = false;
1525ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    if (withinApplication) {
1526ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if(tag == "activity") {
1527ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinActivity = true;
1528ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityName = getAttribute(tree, NAME_ATTR, &error);
1529ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1530ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1531ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1532ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1533ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1535ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1536ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1537ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
1538ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1539ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1540ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1542ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1543ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1544ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
1545ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1546ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1547ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
15490a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            activityBanner = getResolvedAttribute(&res, tree, BANNER_ATTR, &error);
15500a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (error != "") {
15510a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
15520a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                        error.string());
15530a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                goto bail;
15540a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            }
15550a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn
1556ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            int32_t orien = getResolvedIntegerAttribute(&res, tree,
1557ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    SCREEN_ORIENTATION_ATTR, &error);
1558ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error == "") {
1559ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (orien == 0 || orien == 6 || orien == 8) {
1560ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests landscape, sensorLandscape, or reverseLandscape.
15612c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.landscape",
15622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            "one or more activities have specified a landscape orientation");
1563ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else if (orien == 1 || orien == 7 || orien == 9) {
1564ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests portrait, sensorPortrait, or reversePortrait.
15652c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.portrait",
15662c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            "one or more activities have specified a portrait orientation");
1567ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1569ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "uses-library") {
1570ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
1571ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1572ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1573ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for uses-library"
1574ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1575ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1576ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1577ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            int req = getIntegerAttribute(tree,
1578ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    REQUIRED_ATTR, NULL, 1);
1579ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("uses-library%s:'%s'\n",
15802675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    req ? "" : "-not-required", ResTable::normalizeForOutput(
15812675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                            libraryName.string()).string());
1582ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "receiver") {
1583ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinReceiver = true;
1584ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            receiverName = getAttribute(tree, NAME_ATTR, &error);
1585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1586ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1587ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1588ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for receiver:"
1589ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1590ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1591ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1592a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1593a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1594a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1595a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_DEVICE_ADMIN") {
1596a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindDeviceAdminPermission = true;
1597a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1598a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
1599a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1600a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        " receiver '%s': %s\n", receiverName.string(), error.string());
1601a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
1602ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "service") {
1603ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinService = true;
1604ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            serviceName = getAttribute(tree, NAME_ATTR, &error);
1605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1606ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1607ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1608ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "service:%s\n", error.string());
1609ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1610ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1611a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1612a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1613a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1614a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_INPUT_METHOD") {
1615a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindInputMethodPermission = true;
1616a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
1617a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindAccessibilityServicePermission = true;
1618a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
1619a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindPrintServicePermission = true;
162094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                } else if (permission == "android.permission.BIND_NFC_SERVICE") {
162194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasBindNfcServicePermission = true;
16229d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                } else if (permission == "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
16239d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                    hasBindNotificationListenerServicePermission = true;
1624eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                } else if (permission == "android.permission.BIND_DREAM_SERVICE") {
1625eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                    hasBindDreamServicePermission = true;
1626a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1627a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
1628a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1629a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        " service '%s': %s\n", serviceName.string(), error.string());
1630a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
16319d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        } else if (tag == "provider") {
16329d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            withinProvider = true;
16339d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16349d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            bool exported = getResolvedIntegerAttribute(&res, tree, EXPORTED_ATTR, &error);
16359d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
16369d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:exported' attribute for provider:"
16379d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        " %s\n", error.string());
16389d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
16399d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
16409d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16419d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            bool grantUriPermissions = getResolvedIntegerAttribute(&res, tree,
16429d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                    GRANT_URI_PERMISSIONS_ATTR, &error);
16439d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
16449d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:grantUriPermissions' attribute for provider:"
16459d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        " %s\n", error.string());
16469d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
16479d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
16489d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16499d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            String8 permission = getResolvedAttribute(&res, tree, PERMISSION_ATTR, &error);
16509d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
16519d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for provider:"
16529d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        " %s\n", error.string());
16539d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
16549d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
16559d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16569d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            hasRequiredSafAttributes |= exported && grantUriPermissions &&
16579d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                permission == "android.permission.MANAGE_DOCUMENTS";
16589d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
1659ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
1660b71adb6571aa740f4fa794602133f708e1b96545Adam Lesinski                            String8 metaDataName = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
1661ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1662ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1663ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "meta-data:%s\n", error.string());
1664ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1665ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
16662675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("meta-data: name='%s' ",
16672675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(metaDataName.string()).string());
166876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                            printResolvedResourceAttribute(&res, tree, VALUE_ATTR, String8("value"),
166976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                    &error);
1670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
167176327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                // Try looking for a RESOURCE_ATTR
167276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                error = "";
167376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                printResolvedResourceAttribute(&res, tree, RESOURCE_ATTR,
167476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                        String8("resource"), &error);
1675ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (error != "") {
167676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                    fprintf(stderr, "ERROR getting 'android:value' or "
167776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                            "'android:resource' attribute for "
167876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                            "meta-data:%s\n", error.string());
1679ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    goto bail;
1680ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1681ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
168276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                            printf("\n");
1683ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (withinSupportsInput && tag == "input-type") {
1684ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 name = getAttribute(tree, NAME_ATTR, &error);
1685ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (name != "" && error == "") {
1686ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                supportedInput.add(name);
1687ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            } else {
1688ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1689ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
16932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    } else if (withinFeatureGroup && tag == "uses-feature") {
1694d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        FeatureGroup& top = featureGroups.editTop();
1695d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
16962c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        String8 name = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
1697d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        if (name != "" && error == "") {
1698d3edfde51bd069a63e820282421d1a534fcf00ceAdam Lesinski                            top.features.add(name, true);
1699d3edfde51bd069a63e820282421d1a534fcf00ceAdam Lesinski                            addParentFeatures(&top, name);
1700d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        } else {
1701d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            int vers = getIntegerAttribute(tree, GL_ES_VERSION_ATTR, &error);
1702d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            if (error == "") {
1703d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                if (vers > top.openGLESVersion) {
1704d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    top.openGLESVersion = vers;
1705d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                }
1706d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            }
17072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
1708a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
170994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                } else if (depth == 4) {
171094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (tag == "intent-filter") {
171194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        hasIntentFilter = true;
171294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        withinIntentFilter = true;
171394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actMainActivity = false;
171494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actWidgetReceivers = false;
171594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actImeService = false;
171694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actWallpaperService = false;
171794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actAccessibilityService = false;
171894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actPrintService = false;
171994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actDeviceAdminEnabled = false;
172094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actHostApduService = false;
172194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actOffHostApduService = false;
17229d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actDocumentsProvider = false;
17239d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actNotificationListenerService = false;
1724eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                        actDreamService = false;
17259d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actCamera = false;
17269d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actCameraSecure = false;
17279d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        catLauncher = false;
172894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    } else if (withinService && tag == "meta-data") {
172994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
173094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (error != "") {
173194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute for"
173294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
173394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            goto bail;
173494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        }
173594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
173694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (name == "android.nfc.cardemulation.host_apdu_service" ||
173794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                name == "android.nfc.cardemulation.off_host_apdu_service") {
173894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            bool offHost = true;
173994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (name == "android.nfc.cardemulation.host_apdu_service") {
174094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                offHost = false;
174194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
174294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
174394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            String8 xmlPath = getResolvedAttribute(&res, tree, RESOURCE_ATTR, &error);
174494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (error != "") {
174594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:resource' attribute for"
174694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
174794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                goto bail;
174894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
174994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
175094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
175194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    offHost, &error);
175294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (error != "") {
175394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                fprintf(stderr, "ERROR getting AID category for service '%s'\n",
175494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        serviceName.string());
175594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                goto bail;
175694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
175794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
175894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            const size_t catLen = categories.size();
175994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            for (size_t i = 0; i < catLen; i++) {
176094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                bool paymentCategory = (categories[i] == "payment");
176194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                if (offHost) {
176294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasMetaOffHostPaymentCategory |= paymentCategory;
176394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                } else {
176494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasMetaHostPaymentCategory |= paymentCategory;
176594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                }
176694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
176794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        }
176894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
1769a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                } else if ((depth == 5) && withinIntentFilter) {
1770a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    String8 action;
1771a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "action") {
1772a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        action = getAttribute(tree, NAME_ATTR, &error);
1773a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1774a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1775a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1776a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1777a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1778a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1779a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1780a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.intent.action.MAIN") {
1781a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isMainActivity = true;
1782a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actMainActivity = true;
17839d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (action == "android.media.action.STILL_IMAGE_CAMERA" ||
17849d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                    action == "android.media.action.VIDEO_CAMERA") {
17859d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actCamera = true;
17869d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (action == "android.media.action.STILL_IMAGE_CAMERA_SECURE") {
17879d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actCameraSecure = true;
1788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1789a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinReceiver) {
1790a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
1791a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWidgetReceivers = true;
1792a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
1793a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actDeviceAdminEnabled = true;
1794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1795a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinService) {
1796a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.view.InputMethod") {
1797a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actImeService = true;
1798a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.service.wallpaper.WallpaperService") {
1799a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWallpaperService = true;
1800a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.accessibilityservice.AccessibilityService") {
1801a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actAccessibilityService = true;
1802a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.printservice.PrintService") {
1803a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actPrintService = true;
180494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            } else if (action == "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
180594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                actHostApduService = true;
180694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            } else if (action == "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
180794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                actOffHostApduService = true;
18089d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (action == "android.service.notification.NotificationListenerService") {
18099d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actNotificationListenerService = true;
1810eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                            } else if (action == "android.service.dreams.DreamService") {
1811eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                actDreamService = true;
18129d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
18139d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        } else if (withinProvider) {
18149d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (action == "android.content.action.DOCUMENTS_PROVIDER") {
18159d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actDocumentsProvider = true;
1816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1818a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (action == "android.intent.action.SEARCH") {
1819a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            isSearchable = true;
1820a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1821a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
1822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1823a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "category") {
1824a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        String8 category = getAttribute(tree, NAME_ATTR, &error);
1825a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1826a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'name' attribute: %s\n",
1827a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1828a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1829a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1830a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1831a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (category == "android.intent.category.LAUNCHER") {
1832a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isLauncherActivity = true;
18330a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            } else if (category == "android.intent.category.LEANBACK_LAUNCHER") {
18340a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                isLeanbackLauncherActivity = true;
18359d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (category == "android.intent.category.HOME") {
18369d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                catLauncher = true;
1837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-1.6 implicitly granted permission compatibility logic
1844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 4) {
1845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteExternalStoragePermission) {
184658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
184758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
184858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 4"));
1849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasWriteExternalStoragePermission = true;
1850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadPhoneStatePermission) {
185258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.READ_PHONE_STATE"));
185358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"),
185458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 4"));
1855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If the application has requested WRITE_EXTERNAL_STORAGE, we will
1859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // force them to always take READ_EXTERNAL_STORAGE as well.  We always
1860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // do this (regardless of target API version) because we can't have
1861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // an app with write permission but not read permission.
1862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
186358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"));
186458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
186558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                        String8("requested WRITE_EXTERNAL_STORAGE"));
1866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-JellyBean call log permission compatibility.
1869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 16) {
1870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadCallLogPermission && hasReadContactsPermission) {
187158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.READ_CALL_LOG"));
187258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
187358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 16 and requested READ_CONTACTS"));
1874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
187658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.WRITE_CALL_LOG"));
187758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"),
187858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 16 and requested WRITE_CONTACTS"));
1879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
18822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            addImpliedFeature(&impliedFeatures, "android.hardware.touchscreen",
18832c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    "default feature for all apps");
18842c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
18852c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            const size_t numFeatureGroups = featureGroups.size();
18862c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            if (numFeatureGroups == 0) {
18872c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                // If no <feature-group> tags were defined, apply auto-implied features.
18882c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printFeatureGroup(commonFeatures, &impliedFeatures);
18892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
18902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            } else {
18912c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                // <feature-group> tags are defined, so we ignore implied features and
18922c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                for (size_t i = 0; i < numFeatureGroups; i++) {
18932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    FeatureGroup& grp = featureGroups.editItemAt(i);
18942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1895d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                    if (commonFeatures.openGLESVersion > grp.openGLESVersion) {
1896d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        grp.openGLESVersion = commonFeatures.openGLESVersion;
1897d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                    }
1898d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
18992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    // Merge the features defined in the top level (not inside a <feature-group>)
19002c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    // with this feature group.
19012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    const size_t numCommonFeatures = commonFeatures.features.size();
19022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    for (size_t j = 0; j < numCommonFeatures; j++) {
19032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) {
1904d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            grp.features.add(commonFeatures.features.keyAt(j),
1905d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    commonFeatures.features[j]);
19062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
1907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19092c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                   if (!grp.features.isEmpty()) {
19102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        printFeatureGroup(grp);
19112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    }
1912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19152c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWidgetReceivers) {
19179d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("app-widget");
1918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1919a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasDeviceAdminReceiver) {
19209d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("device-admin");
1921a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
1922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasImeService) {
19239d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("ime");
1924282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWallpaperService) {
19269d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("wallpaper");
1927282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1928a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasAccessibilityService) {
19299d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("accessibility");
1930a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
1931a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasPrintService) {
19329d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("print-service");
1933a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
193494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (hasPaymentService) {
19359d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("payment");
19369d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19379d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (isSearchable) {
19389d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("search");
19399d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19409d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasDocumentsProvider) {
19419d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("document-provider");
19429d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19439d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasLauncher) {
19449d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("launcher");
19459d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19469d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasNotificationListenerService) {
19479d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("notification-listener");
19489d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
1949eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            if (hasDreamService) {
1950eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                printComponentPresence("dream");
1951eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            }
19529d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasCameraActivity) {
19539d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("camera");
19549d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19559d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasCameraSecureActivity) {
19569d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("camera-secure");
19579d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19589d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
19599d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasMainActivity) {
19609d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printf("main\n");
196194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
1962282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherActivities) {
1963282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-activities\n");
1964282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
19659d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski             if (hasOtherReceivers) {
1966282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-receivers\n");
1967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherServices) {
1969282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-services\n");
1970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // For modern apps, if screen size buckets haven't been specified
1973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // but the new width ranges have, then infer the buckets from them.
1974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
1975282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    && requiresSmallestWidthDp > 0) {
1976282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int compatWidth = compatibleWidthLimitDp;
1977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (compatWidth <= 0) {
1978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    compatWidth = requiresSmallestWidthDp;
1979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
1981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = -1;
1982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = 0;
1984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
1986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = -1;
1987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = 0;
1989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
1991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = -1;
1992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = 0;
1994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
1996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = -1;
1997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1998282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = 0;
1999282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Determine default values for any unspecified screen sizes,
2003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // based on the target SDK of the package.  As of 4 (donut)
2004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // the screen size support was introduced, so all default to
2005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // enabled.
2006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0) {
2007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                smallScreen = targetSdk >= 4 ? -1 : 0;
2008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen > 0) {
2010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                normalScreen = -1;
2011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen > 0) {
2013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                largeScreen = targetSdk >= 4 ? -1 : 0;
2014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen > 0) {
2016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Introduced in Gingerbread.
2017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                xlargeScreen = targetSdk >= 9 ? -1 : 0;
2018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (anyDensity > 0) {
2020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
2021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        || compatibleWidthLimitDp > 0) ? -1 : 0;
2022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-screens:");
2024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen != 0) {
2025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'small'");
2026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen != 0) {
2028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'normal'");
2029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen != 0) {
2031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'large'");
2032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen != 0) {
2034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'xlarge'");
2035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
2038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (requiresSmallestWidthDp > 0) {
2039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
2040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (compatibleWidthLimitDp > 0) {
2042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
2043282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2044282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largestWidthLimitDp > 0) {
2045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
2046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("locales:");
2049282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NL = locales.size();
2050282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NL; i++) {
2051282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const char* localeStr =  locales[i].string();
2052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (localeStr == NULL || strlen(localeStr) == 0) {
2053282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    localeStr = "--_--";
2054282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'", localeStr);
2056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("densities:");
2060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t ND = densities.size();
2061282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<ND; i++) {
2062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%d'", densities[i]);
2063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2064282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2065282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2066282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
2067282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (dir != NULL) {
2068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dir->getFileCount() > 0) {
2069e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    SortedVector<String8> architectures;
2070282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    for (size_t i=0; i<dir->getFileCount(); i++) {
2071e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        architectures.add(ResTable::normalizeForOutput(
2072e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                dir->getFileName(i).string()));
2073e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    }
2074e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2075e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    bool outputAltNativeCode = false;
2076e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // A multiArch package is one that contains 64-bit and
2077e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 32-bit versions of native code and expects 3rd-party
2078e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // apps to load these native code libraries. Since most
2079e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 64-bit systems also support 32-bit apps, the apps
2080e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // loading this multiArch package's code may be either
2081e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 32-bit or 64-bit.
2082e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    if (hasMultiArch) {
2083e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // If this is a multiArch package, report the 64-bit
2084e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // version only. Then as a separate entry, report the
2085e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // rest.
2086e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        //
2087e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // If we report the 32-bit architecture, this APK will
2088e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // be installed on a 32-bit device, causing a large waste
2089e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // of bandwidth and disk space. This assumes that
2090e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // the developer of the multiArch package has also
2091e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // made a version that is 32-bit only.
2092e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        String8 intel64("x86_64");
2093e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        String8 arm64("arm64-v8a");
2094e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        ssize_t index = architectures.indexOf(intel64);
2095e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (index < 0) {
2096e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            index = architectures.indexOf(arm64);
2097e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2098e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2099e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (index >= 0) {
2100e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf("native-code: '%s'\n", architectures[index].string());
2101e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            architectures.removeAt(index);
2102e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            outputAltNativeCode = true;
2103e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2104e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    }
2105e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2106e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    const size_t archCount = architectures.size();
2107e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    if (archCount > 0) {
2108e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (outputAltNativeCode) {
2109e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf("alt-");
2110e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2111e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        printf("native-code:");
2112e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        for (size_t i = 0; i < archCount; i++) {
2113e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf(" '%s'", architectures[i].string());
2114e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2115e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        printf("\n");
2116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                delete dir;
2119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badger", option) == 0) {
2121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s", CONSOLE_DATA);
2122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("configurations", option) == 0) {
2123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
2124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
2125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = configs.size();
2126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<N; i++) {
2127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("%s\n", configs[i].toString().string());
2128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
2131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
2136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (asset) {
2139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete asset;
2140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "add" command, which wants to add files to a new or
2147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * pre-existing archive.
2148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doAdd(Bundle* bundle)
2150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
2152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
2153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
2154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getUpdate()) {
2156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* avoid confusion */
2157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: can't use '-u' with add\n");
2158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
2162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
2163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
2166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
2168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
2169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, true);
2173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
2174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
2175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
2180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
2182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s'... (from gzip)\n", fileName);
2183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
2184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (bundle->getJunkPath()) {
2186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 storageName = String8(fileName).getPathLeaf();
21872675f769673f69b0661ddee346292f25cb30a296Maurice Chu                printf(" '%s' as '%s'...\n", fileName,
21882675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        ResTable::normalizeForOutput(storageName.string()).string());
2189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, storageName.string(),
2190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  bundle->getCompressionMethod(), NULL);
2191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
2192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'...\n", fileName);
2193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
2194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
2197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
2198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (result == NAME_NOT_FOUND) {
2199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": file not found\n");
2200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (result == ALREADY_EXISTS) {
2201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": already exists in archive\n");
2202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
2203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "\n");
2204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
2210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
2213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Delete files from an existing archive.
2219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doRemove(Bundle* bundle)
2221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
2223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
2224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
2225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
2227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
2228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
2231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
2233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
2234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, false);
2238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
2239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
2240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zipFileName);
2241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
2246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ZipEntry* entry;
2247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByName(fileName);
2249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (entry == NULL) {
2250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s' NOT FOUND\n", fileName);
2251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
2252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = zip->remove(entry);
2255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
2257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to delete '%s' from '%s'\n",
2258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                bundle->getFileSpecEntry(i), zipFileName);
2259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* update the archive */
2264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip->flush();
2265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
2268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
22713921e87e6e67a063caa1987937d7944b24aef489Adam Lesinskistatic status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
2272fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    const size_t numDirs = dir->getDirs().size();
2273fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    for (size_t i = 0; i < numDirs; i++) {
22743921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        bool ignore = ignoreConfig;
22753921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
22763921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        const char* dirStr = subDir->getLeaf().string();
22773921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
22783921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            ignore = true;
22793921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        }
22803921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        status_t err = addResourcesToBuilder(subDir, builder, ignore);
2281fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        if (err != NO_ERROR) {
2282fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            return err;
2283fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2284fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2285fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2286fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    const size_t numFiles = dir->getFiles().size();
2287fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    for (size_t i = 0; i < numFiles; i++) {
2288fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        sp<AaptGroup> gp = dir->getFiles().valueAt(i);
2289fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numConfigs = gp->getFiles().size();
2290fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t j = 0; j < numConfigs; j++) {
22913921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            status_t err = NO_ERROR;
22923921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            if (ignoreConfig) {
22933921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski                err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
22943921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            } else {
22953921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski                err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
22963921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            }
2297fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2298fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "Failed to add %s (%s) to builder.\n",
2299fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                        gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
2300fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                return err;
2301fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2302fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2303fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2304fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    return NO_ERROR;
2305fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski}
2306fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2307fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinskistatic String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
2308fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (split->isBase()) {
2309fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        return original;
2310fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2311fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2312fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    String8 ext(original.getPathExtension());
2313fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (ext == String8(".apk")) {
2314fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        return String8::format("%s_%s%s",
2315fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                original.getBasePath().string(),
2316fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                split->getDirectorySafeName().string(),
2317fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                ext.string());
2318fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2319fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2320fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    return String8::format("%s_%s", original.string(),
2321fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            split->getDirectorySafeName().string());
2322fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski}
2323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Package up an asset directory and associated application files.
2326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doPackage(Bundle* bundle)
2328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* outputAPKFile;
2330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int retVal = 1;
2331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err;
2332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<AaptAssets> assets;
2333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int N;
2334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    FILE* fp;
2335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 dependencyFile;
2336fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    sp<ApkBuilder> builder;
2337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2338a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin    // -c en_XA or/and ar_XB means do pseudolocalization
2339fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
2340fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    err = configFilter->parse(bundle->getConfigurations());
2341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
2342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2344fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (configFilter->containsPseudo()) {
2345a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
2346a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin    }
2347fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (configFilter->containsPseudoBidi()) {
2348a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
2349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    N = bundle->getFileSpecCount();
2352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
235309384303dea4f3f01d5682918d7bab9bf83a02b1Adam Lesinski            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
2354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no input files\n");
2355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    outputAPKFile = bundle->getOutputAPKFile();
2359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make sure the filenames provided exist and are of the appropriate type.
2361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
2362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        FileType type;
2363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        type = getFileType(outputAPKFile);
2364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
2365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr,
2366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                "ERROR: output file '%s' exists but is not regular file\n",
2367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                outputAPKFile);
2368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Load the assets.
2373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets = new AaptAssets();
2374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Set up the resource gathering in assets if we're going to generate
2376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // dependency files. Every time we encounter a resource while slurping
2377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the tree, we'll add it to these stores so we have full resource paths
2378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // to write to a dependency file.
2379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> resPathStore = new FilePathStore;
2381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullResPaths(resPathStore);
2382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> assetPathStore = new FilePathStore;
2383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullAssetPaths(assetPathStore);
2384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = assets->slurpFromArgs(bundle);
2387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
2388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
2392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->print(String8());
2393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2395fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // Create the ApkBuilder, which will collect the compiled files
2396fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // to write to the final APK (or sets of APKs if we are building
2397fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // a Split APK.
2398fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    builder = new ApkBuilder(configFilter);
2399fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2400fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // If we are generating a Split APK, find out which configurations to split on.
2401fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (bundle->getSplitConfigurations().size() > 0) {
2402fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
2403fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numSplits = splitStrs.size();
2404fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t i = 0; i < numSplits; i++) {
2405fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            std::set<ConfigDescription> configs;
2406fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
2407fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
2408fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2409fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2410fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2411fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            err = builder->createSplitForConfigs(configs);
2412fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2413fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2414fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2415fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2416fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2417fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If they asked for any fileAs that need to be compiled, do so.
2419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
2420fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        err = buildResources(bundle, assets, builder);
2421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != 0) {
2422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // At this point we've read everything and processed everything.  From here
2427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // on out it's just writing output files.
2428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Update symbols with information about which ones are needed as Java symbols.
2433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets->applyJavaSymbols();
2434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, do that here
2439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If this is the packaging step, generate the dependency file next to
2441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the output apk (e.g. bin/resources.ap_.d)
2442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outputAPKFile) {
2443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(outputAPKFile);
2444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Add the .d extension to the dependency file.
2445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.append(".d");
2446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Else if this is the R.java dependency generation step,
2448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // generate the dependency file in the R.java package subdirectory
2449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java.d
2450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(bundle->getRClassDir());
2451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.appendPath("R.java.d");
2452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Make sure we have a clean dependency file to start with
2454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "w");
2455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
2456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out R.java constants
2459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets->havePrivateSymbols()) {
2460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getCustomPackage() == NULL) {
2461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Write the R.java file into the appropriate class directory
2462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java
2463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = writeResourceSymbols(bundle, assets, assets->getPackage(), true);
2464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const String8 customPkg(bundle->getCustomPackage());
2466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = writeResourceSymbols(bundle, assets, customPkg, true);
2467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If we have library files, we're going to write our R.java file into
2472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the appropriate class directory for those libraries as well.
2473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // e.g. gen/com/foo/app/lib/R.java
2474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getExtraPackages() != NULL) {
2475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Split on colon
2476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 libs(bundle->getExtraPackages());
2477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
2478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while (packageString != NULL) {
2479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Write the R.java file out with the correct package name
2480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                err = writeResourceSymbols(bundle, assets, String8(packageString), true);
2481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (err < 0) {
2482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    goto bail;
2483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                packageString = strtok(NULL, ":");
2485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            libs.unlockBuffer();
2487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
2489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getPackage(), false);
2490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true);
2494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out the ProGuard file
2500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = writeProguardFile(bundle, assets);
2501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
2502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write the apk
2506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
2507fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        // Gather all resources and add them to the APK Builder. The builder will then
2508fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        // figure out which Split they belong in.
2509fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        err = addResourcesToBuilder(assets, builder);
2510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
2511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2513fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2514fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const Vector<sp<ApkSplit> >& splits = builder->getSplits();
2515fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numSplits = splits.size();
2516fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t i = 0; i < numSplits; i++) {
2517fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            const sp<ApkSplit>& split = splits[i];
2518fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            String8 outputPath = buildApkName(String8(outputAPKFile), split);
2519fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            err = writeAPK(bundle, outputPath, split);
2520fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2521fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
2522fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2523fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2524fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, we need to finish up here.
2528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the writeResourceSymbols and writeAPK functions have already written the target
2529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // half of the dependency file, now we need to write the prerequisites. (files that
2530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the R.java file or .ap_ file depend on)
2531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Now that writeResourceSymbols or writeAPK has taken care of writing
2533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the targets to our dependency file, we'll write the prereqs
2534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "a+");
2535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, " : ");
2536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool includeRaw = (outputAPKFile != NULL);
2537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
2538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Also manually add the AndroidManifeset since it's not under res/ or assets/
2539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // and therefore was not added to our pathstores during slurping
2540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
2541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
2542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    retVal = 0;
2545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        SourcePos::printErrors(stderr);
2548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return retVal;
2550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching
2554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * PRECONDITIONS
2555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -S flag points to a source directory containing drawable* folders
2556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -C flag points to destination directory. The folder structure in the
2557282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *     source directory will be mirrored to the destination (cache) directory
2558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
2559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * POSTCONDITIONS
2560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  Destination directory will be updated to match the PNG files in
25612675f769673f69b0661ddee346292f25cb30a296Maurice Chu *  the source directory.
2562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doCrunch(Bundle* bundle)
2564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching PNG Files in ");
2566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
2567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
2568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    updatePreProcessedCache(bundle);
2570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching on a single flag
2576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -i points to a single png file
2577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -o points to a single png output file
2578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doSingleCrunch(Bundle* bundle)
2580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
2582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
2583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 input(bundle->getSingleCrunchInputFile());
2585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 output(bundle->getSingleCrunchOutputFile());
2586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
2588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // we can't return the status_t as it gets truncate to the lower 8 bits.
2589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 42;
2590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskichar CONSOLE_DATA[2925] = {
2596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
2601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
2602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
2605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
2606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
2609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
2612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
2613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
2616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
2617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
2620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
2623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
2624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2626282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
2627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
2630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
2631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
2634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
2635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
2638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
2641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
2642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
2644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
2645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
2647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
2648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
2649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
2652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
2653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
2654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
2656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
2657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
2658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
2659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
2662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
2663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
2664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
2665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
2666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
2667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
2668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
2670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
2672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
2674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
2675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
2677282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
2678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
2679282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2681282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
2682282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
2684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
2685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2686282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2687282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
2688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
2689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
2695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
2696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
2700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
2703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
2706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
2707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
2713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
2714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
2717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
2718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
2721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
2722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
2723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
2724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
2725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
2728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
2729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
2730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
2731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
2732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
2739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
2742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
2743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
2746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
2747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
2749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
2750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
2753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
2754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10
2759282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  };
2760