Command.cpp revision 43158773b469c2d5b23e52998d0afba9a4b34323
1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Copyright 2006 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Android Asset Packaging Tool main entry point.
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
6ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski#include "AaptXml.h"
7fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski#include "ApkBuilder.h"
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "Bundle.h"
92c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include "Images.h"
102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include "Main.h"
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceFilter.h"
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceTable.h"
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "XMLNode.h"
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
152c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/Errors.h>
162c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/KeyedVector.h>
172c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/List.h>
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/Log.h>
192c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/SortedVector.h>
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/threads.h>
212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/Vector.h>
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <errno.h>
242c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <fcntl.h>
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
266f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez#include <iostream>
276f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez#include <string>
286f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez#include <sstream>
296f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiusing namespace android;
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
32ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski#ifndef AAPT_VERSION
33ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski    #define AAPT_VERSION ""
34ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski#endif
35ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Show version info.  All the cool kids do it.
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doVersion(Bundle* bundle)
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 0) {
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("(ignoring extra arguments)\n");
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
44ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski    printf("Android Asset Packaging Tool, v0.2-" AAPT_VERSION "\n");
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 0;
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read only.  The call fails if the file doesn't exist.
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadOnly(const char* fileName)
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip;
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, ZipFile::kOpenReadOnly);
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result == NAME_NOT_FOUND) {
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' not found\n", fileName);
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (result == PERMISSION_DENIED) {
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fileName);
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read-write.  The file will be created if it doesn't
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * already exist and "okayToCreate" is set.
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadWrite(const char* fileName, bool okayToCreate)
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int flags;
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    flags = ZipFile::kOpenReadWrite;
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (okayToCreate) {
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        flags |= ZipFile::kOpenCreate;
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, flags);
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        zip = NULL;
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return a short string describing the compression method.
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiconst char* compressionName(int method)
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (method == ZipEntry::kCompressStored) {
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Stored";
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (method == ZipEntry::kCompressDeflated) {
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Deflated";
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Unknown";
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return the percent reduction in size (0% == no compression).
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint calcPercent(long uncompressedLen, long compressedLen)
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!uncompressedLen) {
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 0;
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "list" command, which can be a simple file dump or
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * a verbose listing.
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The verbose listing closely matches the output of the Info-ZIP "unzip"
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * command.
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doList(Bundle* bundle)
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int result = 1;
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ZipEntry* entry;
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    long totalUncLen, totalCompLen;
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 1) {
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: specify zip file name (only)\n");
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadOnly(zipFileName);
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int count, i;
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("Archive:  %s\n", zipFileName);
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            " Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name\n");
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            "--------  ------  ------- -----  -------      ----  ----  ------    ----\n");
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    totalUncLen = totalCompLen = 0;
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    count = zip->getNumEntries();
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i = 0; i < count; i++) {
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByIndex(i);
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getVerbose()) {
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char dateBuf[32];
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            time_t when;
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            when = entry->getModWhen();
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                localtime(&when));
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%8ld  %-7.7s %7ld %3d%%  %8zd  %s  %08lx  %s\n",
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getUncompressedLen(),
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                compressionName(entry->getCompressionMethod()),
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getCompressedLen(),
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                calcPercent(entry->getUncompressedLen(),
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            entry->getCompressedLen()),
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (size_t) entry->getLFHOffset(),
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                dateBuf,
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getCRC32(),
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getFileName());
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s\n", entry->getFileName());
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalUncLen += entry->getUncompressedLen();
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalCompLen += entry->getCompressedLen();
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "--------          -------  ---                            -------\n");
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("%8ld          %7ld  %2d%%                            %d files\n",
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalUncLen,
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalCompLen,
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            calcPercent(totalUncLen, totalCompLen),
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zip->getNumEntries());
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getAndroidList()) {
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        AssetManager assets;
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!assets.addAssetPath(String8(zipFileName), NULL)) {
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
218ba3fe56edc1da4dad0d831a1892e7b1c3c20c437Elliott Hughes#ifdef __ANDROID__
219b8dc7bc582ee4acd9d6c1379701a002c5ddbe323Andreas Gampe        static const bool kHaveAndroidOs = true;
220b8dc7bc582ee4acd9d6c1379701a002c5ddbe323Andreas Gampe#else
221b8dc7bc582ee4acd9d6c1379701a002c5ddbe323Andreas Gampe        static const bool kHaveAndroidOs = false;
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
223b8dc7bc582ee4acd9d6c1379701a002c5ddbe323Andreas Gampe        const ResTable& res = assets.getResources(false);
224b8dc7bc582ee4acd9d6c1379701a002c5ddbe323Andreas Gampe        if (!kHaveAndroidOs) {
225b8dc7bc582ee4acd9d6c1379701a002c5ddbe323Andreas Gampe            printf("\nResource table:\n");
226b8dc7bc582ee4acd9d6c1379701a002c5ddbe323Andreas Gampe            res.print(false);
227b8dc7bc582ee4acd9d6c1379701a002c5ddbe323Andreas Gampe        }
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                   Asset::ACCESS_BUFFER);
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (manifestAsset == NULL) {
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo AndroidManifest.xml found.\n");
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nAndroid manifest:\n");
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree tree;
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.setTo(manifestAsset->getBuffer(true),
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       manifestAsset->getLength());
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete manifestAsset;
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = 0;
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
250ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinskistatic void printResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree,
25176327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        uint32_t attrRes, String8 attrLabel, String8* outError)
25276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu{
25376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    Res_value value;
254ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    AaptXml::getResolvedResourceAttribute(resTable, tree, attrRes, &value, outError);
25576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (*outError != "") {
25676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        *outError = "error print resolved resource attribute";
25776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        return;
25876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
25976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (value.dataType == Res_value::TYPE_STRING) {
260ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        String8 result = AaptXml::getResolvedAttribute(resTable, tree, attrRes, outError);
2612675f769673f69b0661ddee346292f25cb30a296Maurice Chu        printf("%s='%s'", attrLabel.string(),
2622675f769673f69b0661ddee346292f25cb30a296Maurice Chu                ResTable::normalizeForOutput(result.string()).string());
26376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
26476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu            value.dataType <= Res_value::TYPE_LAST_INT) {
26576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='%d'", attrLabel.string(), value.data);
26676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else {
26776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='0x%x'", attrLabel.string(), (int)value.data);
26876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
26976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu}
27076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// These are attribute resource constants for the platform, as found
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// in android.R.attr
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskienum {
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LABEL_ATTR = 0x01010001,
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ICON_ATTR = 0x01010002,
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NAME_ATTR = 0x01010003,
277a5018c900f126ee8424c82497f32983873db741bAdam Lesinski    PERMISSION_ATTR = 0x01010006,
2789d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    EXPORTED_ATTR = 0x01010010,
2799d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
28094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    RESOURCE_ATTR = 0x01010025,
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    DEBUGGABLE_ATTR = 0x0101000f,
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VALUE_ATTR = 0x01010024,
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_CODE_ATTR = 0x0101021b,
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_NAME_ATTR = 0x0101021c,
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_ORIENTATION_ATTR = 0x0101001e,
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MIN_SDK_VERSION_ATTR = 0x0101020c,
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MAX_SDK_VERSION_ATTR = 0x01010271,
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_TOUCH_SCREEN_ATTR = 0x01010227,
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_HARD_KEYBOARD_ATTR = 0x01010229,
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_NAVIGATION_ATTR = 0x0101022a,
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TARGET_SDK_VERSION_ATTR = 0x01010270,
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TEST_ONLY_ATTR = 0x01010272,
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ANY_DENSITY_ATTR = 0x0101026c,
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    GL_ES_VERSION_ATTR = 0x01010281,
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SMALL_SCREEN_ATTR = 0x01010284,
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NORMAL_SCREEN_ATTR = 0x01010285,
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGE_SCREEN_ATTR = 0x01010286,
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    XLARGE_SCREEN_ATTR = 0x010102bf,
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRED_ATTR = 0x0101028e,
302caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski    INSTALL_LOCATION_ATTR = 0x010102b7,
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_SIZE_ATTR = 0x010102ca,
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_DENSITY_ATTR = 0x010102cb,
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    PUBLIC_KEY_ATTR = 0x010103a6,
30994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    CATEGORY_ATTR = 0x010103e8,
3100a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn    BANNER_ATTR = 0x10103f2,
311d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn    ISGAME_ATTR = 0x10103f4,
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3142675f769673f69b0661ddee346292f25cb30a296Maurice ChuString8 getComponentName(String8 &pkgName, String8 &componentName) {
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = componentName.find(".");
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 retStr(pkgName);
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx == 0) {
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (idx < 0) {
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += ".";
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
3232675f769673f69b0661ddee346292f25cb30a296Maurice Chu        return componentName;
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3252675f769673f69b0661ddee346292f25cb30a296Maurice Chu    return retStr;
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3289cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinskistatic void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResXMLTree::event_code_t code;
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int depth = 0;
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool first = true;
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("compatible-screens:");
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code == ResXMLTree::END_TAG) {
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            depth--;
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (depth < 0) {
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code != ResXMLTree::START_TAG) {
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        depth++;
3469cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        const char16_t* ctag16 = tree.getElementName(&len);
3479cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        if (ctag16 == NULL) {
3489cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            *outError = "failed to get XML element name (bad string pool)";
3499cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            return;
3509cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        }
3519cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        String8 tag(ctag16);
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tag == "screen") {
353ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            int32_t screenSize = AaptXml::getIntegerAttribute(tree,
354ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    SCREEN_SIZE_ATTR);
355ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            int32_t screenDensity = AaptXml::getIntegerAttribute(tree,
356ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    SCREEN_DENSITY_ATTR);
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (screenSize > 0 && screenDensity > 0) {
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!first) {
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf(",");
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                first = false;
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("'%d/%d'", screenSize, screenDensity);
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("\n");
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
36958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
37058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
37158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (maxSdkVersion != -1) {
37258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski         printf(" maxSdkVersion='%d'", maxSdkVersion);
37358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
37458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("\n");
37558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
37658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (optional) {
37758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("optional-permission: name='%s'",
37858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                ResTable::normalizeForOutput(name.string()).string());
37958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        if (maxSdkVersion != -1) {
38058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            printf(" maxSdkVersion='%d'", maxSdkVersion);
38158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        }
38258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("\n");
38358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
38458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
38558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
3865f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinskistatic void printUsesPermissionSdk23(const String8& name, int maxSdkVersion=-1) {
3875f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    printf("uses-permission-sdk-23: ");
3885f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
3895f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    printf("name='%s'", ResTable::normalizeForOutput(name.string()).string());
3905f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    if (maxSdkVersion != -1) {
3915f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        printf(" maxSdkVersion='%d'", maxSdkVersion);
3925f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    }
3935f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    printf("\n");
3945f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski}
3955f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
39658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesImpliedPermission(const String8& name, const String8& reason) {
39758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-implied-permission: name='%s' reason='%s'\n",
39858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(name.string()).string(),
39958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(reason.string()).string());
40058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
40158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
40294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam LesinskiVector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost,
40394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        String8 *outError = NULL)
40494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski{
40594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
40694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    if (aidAsset == NULL) {
40794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (outError != NULL) *outError = "xml resource does not exist";
40894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        return Vector<String8>();
40994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
41094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
41194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
41294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
41394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    bool withinApduService = false;
41494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Vector<String8> categories;
41594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
41694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    String8 error;
41794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree tree;
41894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
41994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
42094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    size_t len;
42194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    int depth = 0;
42294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree::event_code_t code;
42394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
42494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (code == ResXMLTree::END_TAG) {
42594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth--;
4269cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
4279cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
4289cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
4299cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
4309cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
4319cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
43294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
43394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 0 && tag == serviceTagName) {
43494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                withinApduService = false;
43594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
43694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
43794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        } else if (code == ResXMLTree::START_TAG) {
43894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth++;
4399cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
4409cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
4419cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
4429cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
4439cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
4449cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
44594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
44694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 1) {
44794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == serviceTagName) {
44894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    withinApduService = true;
44994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
45094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            } else if (depth == 2 && withinApduService) {
45194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == "aid-group") {
452ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    String8 category = AaptXml::getAttribute(tree, CATEGORY_ATTR, &error);
45394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (error != "") {
45494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (outError != NULL) *outError = error;
45594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        return Vector<String8>();
45694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
45794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
45894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    categories.add(category);
45994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
46094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
46194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        }
46294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
46394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    aidAsset->close();
46494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    return categories;
46594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski}
46694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
4679d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinskistatic void printComponentPresence(const char* componentName) {
4689d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    printf("provides-component:'%s'\n", componentName);
4699d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski}
4709d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
4712c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
4722c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a feature that has been automatically added due to
4732c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * a pre-requisite or some other reason.
4742c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
4752c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct ImpliedFeature {
4765f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    ImpliedFeature() : impliedBySdk23(false) {}
4775f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    ImpliedFeature(const String8& n, bool sdk23) : name(n), impliedBySdk23(sdk23) {}
4785f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
4792c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
4802c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Name of the implied feature.
4812c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
4822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name;
4832c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
4842c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
4855f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski     * Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)?
4865f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski     */
4875f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    bool impliedBySdk23;
4885f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
4895f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    /**
4902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * List of human-readable reasons for why this feature was implied.
4912c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
4922c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    SortedVector<String8> reasons;
4932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
4942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
495694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinskistruct Feature {
496694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    Feature() : required(false), version(-1) {}
497694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    Feature(bool required, int32_t version = -1) : required(required), version(version) {}
498694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
499694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    /**
500694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski     * Whether the feature is required.
501694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski     */
502694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    bool required;
503694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
504694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    /**
505694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski     * What version of the feature is requested.
506694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski     */
507694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    int32_t version;
508694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski};
509694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
5102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
5112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a <feature-group> tag in the AndroidManifest.xml
5122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
5132c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct FeatureGroup {
514d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    FeatureGroup() : openGLESVersion(-1) {}
515d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
5162c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
5172c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Human readable label
5182c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
5192c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 label;
5202c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
5222c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Explicit features defined in the group
5232c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
524694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    KeyedVector<String8, Feature> features;
525d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
526d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    /**
527d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     * OpenGL ES version required
528d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     */
529d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    int openGLESVersion;
5302c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
5312c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
532ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinskistatic bool hasFeature(const char* name, const FeatureGroup& grp,
533ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski                       const KeyedVector<String8, ImpliedFeature>& implied) {
534ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    String8 name8(name);
535ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    ssize_t idx = grp.features.indexOfKey(name8);
536ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    if (idx < 0) {
537ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski        idx = implied.indexOfKey(name8);
538ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    }
539ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    return idx >= 0;
540ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski}
541ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski
5422c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
54343158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              const char* name, const String8& reason, bool sdk23) {
5442c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name8(name);
5452c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    ssize_t idx = impliedFeatures->indexOfKey(name8);
5462c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (idx < 0) {
5475f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        idx = impliedFeatures->add(name8, ImpliedFeature(name8, sdk23));
5482c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
5495f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
5505f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    ImpliedFeature* feature = &impliedFeatures->editValueAt(idx);
5515f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
5525f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    // A non-sdk 23 implied feature takes precedence.
5535f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    if (feature->impliedBySdk23 && !sdk23) {
5545f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        feature->impliedBySdk23 = false;
5555f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    }
55643158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski    feature->reasons.add(reason);
5572c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
5582c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5595f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinskistatic void printFeatureGroupImpl(const FeatureGroup& grp,
5605f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                  const KeyedVector<String8, ImpliedFeature>* impliedFeatures) {
5612c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    printf("feature-group: label='%s'\n", grp.label.string());
5622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
563d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    if (grp.openGLESVersion > 0) {
564d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        printf("  uses-gl-es: '0x%x'\n", grp.openGLESVersion);
565d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    }
566d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
5672c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numFeatures = grp.features.size();
5682c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numFeatures; i++) {
569694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        const Feature& feature = grp.features[i];
570694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        const bool required = feature.required;
571694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        const int32_t version = feature.version;
5722c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5732c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const String8& featureName = grp.features.keyAt(i);
574694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        printf("  uses-feature%s: name='%s'", (required ? "" : "-not-required"),
5752c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                ResTable::normalizeForOutput(featureName.string()).string());
576694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
577694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        if (version > 0) {
578694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski            printf(" version='%d'", version);
579694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        }
580694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        printf("\n");
5812c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
5822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5832c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numImpliedFeatures =
5842c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        (impliedFeatures != NULL) ? impliedFeatures->size() : 0;
5852c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numImpliedFeatures; i++) {
5862c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i);
5872c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        if (grp.features.indexOfKey(impliedFeature.name) >= 0) {
5882c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // The feature is explicitly set, no need to use implied
5892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // definition.
5902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            continue;
5912c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
5922c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        String8 printableFeatureName(ResTable::normalizeForOutput(
5942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    impliedFeature.name.string()));
5955f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        const char* sdk23Suffix = impliedFeature.impliedBySdk23 ? "-sdk-23" : "";
5965f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
5975f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        printf("  uses-feature%s: name='%s'\n", sdk23Suffix, printableFeatureName.string());
5985f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        printf("  uses-implied-feature%s: name='%s' reason='", sdk23Suffix,
5995f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               printableFeatureName.string());
6002c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const size_t numReasons = impliedFeature.reasons.size();
6012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        for (size_t j = 0; j < numReasons; j++) {
6022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            printf("%s", impliedFeature.reasons[j].string());
6032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            if (j + 2 < numReasons) {
6042c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", ");
6052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            } else if (j + 1 < numReasons) {
6062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", and ");
6072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            }
6082c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6092c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("'\n");
6102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
6122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6135f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinskistatic void printFeatureGroup(const FeatureGroup& grp) {
6145f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    printFeatureGroupImpl(grp, NULL);
6155f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski}
6165f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
6175f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinskistatic void printDefaultFeatureGroup(const FeatureGroup& grp,
6185f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                     const KeyedVector<String8, ImpliedFeature>& impliedFeatures) {
6195f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    printFeatureGroupImpl(grp, &impliedFeatures);
6205f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski}
6215f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
6222c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addParentFeatures(FeatureGroup* grp, const String8& name) {
6232c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (name == "android.hardware.camera.autofocus" ||
6242c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.camera.flash") {
625694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        grp->features.add(String8("android.hardware.camera"), Feature(true));
6262c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.location.gps" ||
6272c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.location.network") {
628694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        grp->features.add(String8("android.hardware.location"), Feature(true));
629ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    } else if (name == "android.hardware.faketouch.multitouch") {
630ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski        grp->features.add(String8("android.hardware.faketouch"), Feature(true));
631ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
632ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski            name == "android.hardware.faketouch.multitouch.jazzhands") {
633ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski        grp->features.add(String8("android.hardware.faketouch.multitouch"), Feature(true));
634ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski        grp->features.add(String8("android.hardware.faketouch"), Feature(true));
6352c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch") {
636694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
637ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
638ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski            name == "android.hardware.touchscreen.multitouch.jazzhands") {
639694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen.multitouch"), Feature(true));
640694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
641d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    } else if (name == "android.hardware.opengles.aep") {
642d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        const int openGLESVersion31 = 0x00030001;
643d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        if (openGLESVersion31 > grp->openGLESVersion) {
644d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski            grp->openGLESVersion = openGLESVersion31;
645d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        }
6462c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6472c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
6482c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6495f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinskistatic void addImpliedFeaturesForPermission(const int targetSdk, const String8& name,
6505f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                            KeyedVector<String8, ImpliedFeature>* impliedFeatures,
6515f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                            bool impliedBySdk23Permission) {
6525f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    if (name == "android.permission.CAMERA") {
6535f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.camera",
65443158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8::format("requested %s permission", name.string()),
65543158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
6565f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
65743158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski        if (targetSdk < SDK_LOLLIPOP) {
65843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
65943158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("requested %s permission", name.string()),
66043158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
66143158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
66243158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
66343158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
66443158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski        }
6655f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.location",
66643158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                String8::format("requested %s permission", name.string()),
66743158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                impliedBySdk23Permission);
6685f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
66943158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski        if (targetSdk < SDK_LOLLIPOP) {
67043158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.location.network",
67143158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("requested %s permission", name.string()),
67243158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
67343158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.location.network",
67443158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
67543158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
67643158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski        }
6775f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.location",
67843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8::format("requested %s permission", name.string()),
67943158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
68043158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski    } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
68143158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski               name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
6825f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.INSTALL_LOCATION_PROVIDER") {
6835f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.location",
68443158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8::format("requested %s permission", name.string()),
68543158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
6865f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.BLUETOOTH" ||
6875f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.BLUETOOTH_ADMIN") {
68843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski        if (targetSdk > SDK_DONUT) {
6895f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
69043158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("requested %s permission", name.string()),
69143158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
6925f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
69343158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("targetSdkVersion > %d", SDK_DONUT),
69443158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
6955f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        }
6965f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.RECORD_AUDIO") {
6975f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.microphone",
69843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8::format("requested %s permission", name.string()),
69943158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
7005f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
7015f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.CHANGE_WIFI_STATE" ||
7025f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
7035f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.wifi",
70443158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8::format("requested %s permission", name.string()),
70543158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
7065f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.CALL_PHONE" ||
7075f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.CALL_PRIVILEGED" ||
7085f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.MODIFY_PHONE_STATE" ||
7095f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.PROCESS_OUTGOING_CALLS" ||
7105f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.READ_SMS" ||
7115f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.RECEIVE_SMS" ||
7125f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.RECEIVE_MMS" ||
7135f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.RECEIVE_WAP_PUSH" ||
7145f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.SEND_SMS" ||
7155f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.WRITE_APN_SETTINGS" ||
7165f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.WRITE_SMS") {
7175f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.telephony",
71843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8("requested a telephony permission"),
71943158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
7205f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    }
7215f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski}
7225f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "dump" command, to extract select data from an archive.
725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiextern char CONSOLE_DATA[2925]; // see EOF
727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doDump(Bundle* bundle)
728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump option specified\n");
733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump file specified\n");
738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* option = bundle->getFileSpecEntry(0);
742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* filename = bundle->getFileSpecEntry(1);
743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    AssetManager assets;
745f85e41f29a0e9313c2d4725f9d9648591ea49f3bNarayan Kamath    int32_t assetsCookie;
746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make a dummy config for retrieving resources...  we need to supply
752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // non-default values for some configs so that we can retrieve resources
753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // in the app that don't have a default.  The most important of these is
754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the API version because key resources like icons will have an implicit
755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // version if they are using newer config types like density.
756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_config config;
75791447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath    memset(&config, 0, sizeof(ResTable_config));
758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[0] = 'e';
759282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[1] = 'n';
760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[0] = 'U';
761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[1] = 'S';
762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.orientation = ResTable_config::ORIENTATION_PORT;
763282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.density = ResTable_config::DENSITY_MEDIUM;
764282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.sdkVersion = 10000; // Very high.
765282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenWidthDp = 320;
766282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenHeightDp = 480;
767282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.smallestScreenWidthDp = 320;
768c2dea8daea2ae0001d56689d96ce1066012b7b40Adam Lesinski    config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL;
769282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets.setConfiguration(config);
770282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
771282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ResTable& res = assets.getResources(false);
7726800165351b693fa7e4bcf0f205655f0cd16b361Dan Albert    if (res.getError() != NO_ERROR) {
77325e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
77463e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        return 1;
77563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    }
77663e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski
777694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    // Source for AndroidManifest.xml
778694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    const String8 manifestFile = String8::format("%s@AndroidManifest.xml", filename);
779694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
7802cb761e3ddb9d68ab430013e9cd15ecaab9fbc62Adam Lesinski    // The dynamicRefTable can be null if there are no resources for this asset cookie.
7812cb761e3ddb9d68ab430013e9cd15ecaab9fbc62Adam Lesinski    // This fine.
78263e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie);
783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
78463e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    Asset* asset = NULL;
78563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski
786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strcmp("resources", option) == 0) {
787ba3fe56edc1da4dad0d831a1892e7b1c3c20c437Elliott Hughes#ifndef __ANDROID__
788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        res.print(bundle->getValues());
789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
791282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("strings", option) == 0) {
792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResStringPool* pool = res.getTableStringBlock(0);
793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printStringPool(pool);
794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
795282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmltree", option) == 0) {
796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
80363e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            ResXMLTree tree(dynamicRefTable);
80463e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.restart();
816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.uninit();
818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmlstrings", option) == 0) {
823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
826282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
827282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
828282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
83063e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
83663e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            ResXMLTree tree(dynamicRefTable);
837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printStringPool(&tree.getStrings());
843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
84863e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER);
849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (asset == NULL) {
850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
85463e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        ResXMLTree tree(dynamicRefTable);
855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.setTo(asset->getBuffer(true),
856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       asset->getLength()) != NO_ERROR) {
857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        tree.restart();
861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcmp("permissions", option) == 0) {
863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
8665f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
8675f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                    code != ResXMLTree::BAD_DOCUMENT) {
868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
8769cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                const char16_t* ctag16 = tree.getElementName(&len);
8779cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                if (ctag16 == NULL) {
8789cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
8799cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    goto bail;
8809cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                }
8819cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                String8 tag(ctag16);
882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d tag %s\n", depth, tag.string());
883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
888ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
8892675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
8905f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                } else if (depth == 2) {
8915f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                    if (tag == "permission") {
8925f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        String8 error;
8935f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
8945f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        if (error != "") {
8955f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            fprintf(stderr, "ERROR: %s\n", error.string());
8965f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            goto bail;
8975f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        }
8985f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
8995f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        if (name == "") {
9005f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            fprintf(stderr, "ERROR: missing 'android:name' for permission\n");
9015f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            goto bail;
9025f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        }
9035f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        printf("permission: %s\n",
9045f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                ResTable::normalizeForOutput(name.string()).string());
9055f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                    } else if (tag == "uses-permission") {
9065f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        String8 error;
9075f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
9085f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        if (error != "") {
9095f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            fprintf(stderr, "ERROR: %s\n", error.string());
9105f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            goto bail;
9115f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        }
9125f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
9135f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        if (name == "") {
9145f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            fprintf(stderr, "ERROR: missing 'android:name' for uses-permission\n");
9155f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            goto bail;
9165f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        }
9175f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        printUsesPermission(name,
9185f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
9195f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
9205f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                    } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
9215f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        String8 error;
9225f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
9235f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        if (error != "") {
9245f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            fprintf(stderr, "ERROR: %s\n", error.string());
9255f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            goto bail;
9265f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        }
9275f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
9285f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        if (name == "") {
9295f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            fprintf(stderr, "ERROR: missing 'android:name' for "
9305f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                    "uses-permission-sdk-23\n");
9315f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            goto bail;
9325f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        }
9335f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        printUsesPermissionSdk23(
9345f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                name,
9355f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
937282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
938282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badging", option) == 0) {
940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<String8> locales;
941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getLocales(&locales);
942282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
943282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
945282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            SortedVector<int> densities;
946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NC = configs.size();
947282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NC; i++) {
948282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int dens = configs[i].density;
949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dens == 0) {
950282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    dens = 160;
951282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
952282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                densities.add(dens);
953282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
954282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
955282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
956282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
957282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
958282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 error;
959282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinActivity = false;
960282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isMainActivity = false;
961282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isLauncherActivity = false;
9620a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            bool isLeanbackLauncherActivity = false;
963282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isSearchable = false;
964282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinApplication = false;
965ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            bool withinSupportsInput = false;
9662c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            bool withinFeatureGroup = false;
967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinReceiver = false;
968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinService = false;
9699d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool withinProvider = false;
970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinIntentFilter = false;
971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasMainActivity = false;
972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherActivities = false;
973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherReceivers = false;
974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherServices = false;
9759d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasIntentFilter = false;
9769d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWallpaperService = false;
978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasImeService = false;
979a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasAccessibilityService = false;
980a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasPrintService = false;
981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWidgetReceivers = false;
982a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasDeviceAdminReceiver = false;
98394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasPaymentService = false;
9849d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasDocumentsProvider = false;
9859d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasCameraActivity = false;
9869d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasCameraSecureActivity = false;
9879d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasLauncher = false;
9889d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasNotificationListenerService = false;
989eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool hasDreamService = false;
9909d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actMainActivity = false;
992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWidgetReceivers = false;
993a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actDeviceAdminEnabled = false;
994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actImeService = false;
995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWallpaperService = false;
996a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actAccessibilityService = false;
997a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actPrintService = false;
99894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actHostApduService = false;
99994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actOffHostApduService = false;
10009d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actDocumentsProvider = false;
10019d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actNotificationListenerService = false;
1002eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool actDreamService = false;
10039d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actCamera = false;
10049d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actCameraSecure = false;
10059d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool catLauncher = false;
100694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaHostPaymentCategory = false;
100794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaOffHostPaymentCategory = false;
1008a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1009a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // These permissions are required by services implementing services
1010a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // the system binds to (IME, Accessibility, PrintServices, etc.)
1011a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindDeviceAdminPermission = false;
1012a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindInputMethodPermission = false;
1013a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindAccessibilityServicePermission = false;
1014a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindPrintServicePermission = false;
101594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasBindNfcServicePermission = false;
10169d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasRequiredSafAttributes = false;
10179d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasBindNotificationListenerServicePermission = false;
1018eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool hasBindDreamServicePermission = false;
1019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // These two implement the implicit permissions that are granted
1021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // to pre-1.6 applications.
1022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteExternalStoragePermission = false;
1023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadPhoneStatePermission = false;
1024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If an app requests write storage, they will also get read storage.
1026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadExternalStoragePermission = false;
1027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Implement transition to read and write call log.
1029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadContactsPermission = false;
1030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteContactsPermission = false;
1031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadCallLogPermission = false;
1032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteCallLogPermission = false;
1033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1034e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            // If an app declares itself as multiArch, we report the
1035e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            // native libraries differently.
1036e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            bool hasMultiArch = false;
1037e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
1038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This next group of variables is used to implement a group of
1039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // backward-compatibility heuristics necessitated by the addition of
1040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // some new uses-feature constants in 2.1 and 2.2. In most cases, the
1041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // heuristic is "if an app requests a permission but doesn't explicitly
1042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // request the corresponding <uses-feature>, presume it's there anyway".
10432c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1044282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // 2.2 also added some other features that apps can request, but that
1045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // have no corresponding permission, so we cannot implement any
1046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // back-compatibility heuristic for them. The below are thus unnecessary
1047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // (but are retained here for documentary purposes.)
1048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specCompassFeature = false;
1049282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAccelerometerFeature = false;
1050282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specProximityFeature = false;
1051282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAmbientLightFeature = false;
1052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specLiveWallpaperFeature = false;
1053282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1054282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int targetSdk = 0;
1055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int smallScreen = 1;
1056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int normalScreen = 1;
1057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largeScreen = 1;
1058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int xlargeScreen = 1;
1059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int anyDensity = 1;
1060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int requiresSmallestWidthDp = 0;
1061282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int compatibleWidthLimitDp = 0;
1062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largestWidthLimitDp = 0;
1063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 pkg;
1064282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityName;
1065282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityLabel;
1066282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityIcon;
10670a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            String8 activityBanner;
1068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 receiverName;
1069282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 serviceName;
1070ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            Vector<String8> supportedInput;
10712c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
10722c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            FeatureGroup commonFeatures;
10732c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            Vector<FeatureGroup> featureGroups;
10742c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            KeyedVector<String8, ImpliedFeature> impliedFeatures;
10752c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
10765f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
10775f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                    code != ResXMLTree::BAD_DOCUMENT) {
1078282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
1079282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
1080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (depth < 2) {
1081ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if (withinSupportsInput && !supportedInput.isEmpty()) {
1082ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("supports-input: '");
1083ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            const size_t N = supportedInput.size();
1084ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            for (size_t i=0; i<N; i++) {
10852675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                printf("%s", ResTable::normalizeForOutput(
10862675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        supportedInput[i].string()).string());
1087ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (i != N - 1) {
1088ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("' '");
1089ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else {
1090ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("'\n");
1091ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1092ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1093ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            supportedInput.clear();
1094ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        }
1095282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = false;
1096ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = false;
10972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        withinFeatureGroup = false;
1098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 3) {
10990a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                        if (withinActivity && isMainActivity) {
11002675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            String8 aName(getComponentName(pkg, activityName));
11010a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (isLauncherActivity) {
11020a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf("launchable-activity:");
11039eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                if (aName.length() > 0) {
11049eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                    printf(" name='%s' ",
11059eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                            ResTable::normalizeForOutput(aName.string()).string());
11060a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                }
11070a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf(" label='%s' icon='%s'\n",
11085f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                       ResTable::normalizeForOutput(activityLabel.string())
11095f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                                .string(),
11105f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                       ResTable::normalizeForOutput(activityIcon.string())
11115f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                                .string());
11120a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            }
11130a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (isLeanbackLauncherActivity) {
11140a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf("leanback-launchable-activity:");
11159eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                if (aName.length() > 0) {
11169eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                    printf(" name='%s' ",
11179eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                            ResTable::normalizeForOutput(aName.string()).string());
11180a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                }
11190a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf(" label='%s' icon='%s' banner='%s'\n",
11205f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                       ResTable::normalizeForOutput(activityLabel.string())
11215f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                                .string(),
11225f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                       ResTable::normalizeForOutput(activityIcon.string())
11235f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                                .string(),
11245f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                       ResTable::normalizeForOutput(activityBanner.string())
11255f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                                .string());
1126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (!hasIntentFilter) {
1129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherActivities |= withinActivity;
1130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherReceivers |= withinReceiver;
1131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherServices |= withinService;
113294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        } else {
113394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (withinService) {
113494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
113594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        hasBindNfcServicePermission);
113694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
113794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        hasBindNfcServicePermission);
113894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
1139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinActivity = false;
1141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinService = false;
1142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinReceiver = false;
11439d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        withinProvider = false;
1144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasIntentFilter = false;
11450a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                        isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false;
1146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 4) {
1147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (withinIntentFilter) {
1148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (withinActivity) {
1149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasMainActivity |= actMainActivity;
11509d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasLauncher |= catLauncher;
11519d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasCameraActivity |= actCamera;
11529d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasCameraSecureActivity |= actCameraSecure;
11535f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                hasOtherActivities |=
11545f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        !actMainActivity && !actCamera && !actCameraSecure;
1155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinReceiver) {
1156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWidgetReceivers |= actWidgetReceivers;
1157a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
1158a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindDeviceAdminPermission);
11595f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                hasOtherReceivers |=
11605f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        (!actWidgetReceivers && !actDeviceAdminEnabled);
1161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinService) {
1162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasImeService |= actImeService;
1163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWallpaperService |= actWallpaperService;
1164a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasAccessibilityService |= (actAccessibilityService &&
1165a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindAccessibilityServicePermission);
11665f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                hasPrintService |=
11675f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        (actPrintService && hasBindPrintServicePermission);
11689d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasNotificationListenerService |= actNotificationListenerService &&
11699d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        hasBindNotificationListenerServicePermission;
1170eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                hasDreamService |= actDreamService && hasBindDreamServicePermission;
1171a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasOtherServices |= (!actImeService && !actWallpaperService &&
117294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        !actAccessibilityService && !actPrintService &&
11739d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        !actHostApduService && !actOffHostApduService &&
11749d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        !actNotificationListenerService);
11759d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (withinProvider) {
11765f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                hasDocumentsProvider |=
11775f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        actDocumentsProvider && hasRequiredSafAttributes;
1178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinIntentFilter = false;
1181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
1183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
1185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
1186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
11889cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski
11899cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                const char16_t* ctag16 = tree.getElementName(&len);
11909cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                if (ctag16 == NULL) {
11919cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
11929cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    goto bail;
11939cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                }
11949cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                String8 tag(ctag16);
1195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d,  %s\n", depth, tag.string());
1196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
1197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
1198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
1199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1201ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
12022675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("package: name='%s' ",
12032675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(pkg.string()).string());
1204ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR,
1205ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            &error);
1206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
1207ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n",
1208ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                error.string());
1209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (versionCode > 0) {
1212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='%d' ", versionCode);
1213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
1214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='' ");
1215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1216ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    String8 versionName = AaptXml::getResolvedAttribute(res, tree,
1217ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            VERSION_NAME_ATTR, &error);
1218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
1219ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n",
1220ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                error.string());
1221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
122325d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    printf("versionName='%s'",
12242675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(versionName.string()).string());
122525d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski
1226ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    String8 splitName = AaptXml::getAttribute(tree, NULL, "split");
122725d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    if (!splitName.isEmpty()) {
122825d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                        printf(" split='%s'", ResTable::normalizeForOutput(
122925d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                                    splitName.string()).string());
123025d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    }
1231ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
12325283faba4a75a4d1fd9990637d22768e423895e3Adam Lesinski                    String8 platformVersionName = AaptXml::getAttribute(tree, NULL,
12335283faba4a75a4d1fd9990637d22768e423895e3Adam Lesinski                            "platformBuildVersionName");
12345283faba4a75a4d1fd9990637d22768e423895e3Adam Lesinski                    printf(" platformBuildVersionName='%s'", platformVersionName.string());
123525d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    printf("\n");
1236caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski
1237ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree,
1238ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            INSTALL_LOCATION_ATTR, &error);
1239caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                    if (error != "") {
1240caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:installLocation' attribute: %s\n",
1241caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                error.string());
1242caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        goto bail;
1243caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                    }
1244caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski
1245caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                    if (installLocation >= 0) {
1246caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        printf("install-location:'");
1247caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        switch (installLocation) {
1248caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                            case 0:
1249caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                printf("auto");
1250caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                break;
1251caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                            case 1:
1252caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                printf("internalOnly");
1253caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                break;
1254caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                            case 2:
1255caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                printf("preferExternal");
1256caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                break;
1257caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                            default:
1258caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                fprintf(stderr, "Invalid installLocation %d\n", installLocation);
1259caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                goto bail;
1260caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        }
1261caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        printf("'\n");
1262caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                    }
1263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2) {
1264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinApplication = false;
1265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag == "application") {
1266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = true;
1267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 label;
1269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t NL = locales.size();
1270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<NL; i++) {
1271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char* localeStr =  locales[i].string();
1272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setLocale(localeStr != NULL ? localeStr : "");
1273ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            String8 llabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
1274ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    &error);
1275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (llabel != "") {
1276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                if (localeStr == NULL || strlen(localeStr) == 0) {
1277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    label = llabel;
12782675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    printf("application-label:'%s'\n",
12792675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                            ResTable::normalizeForOutput(llabel.string()).string());
1280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                } else {
1281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    if (label == "") {
1282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        label = llabel;
1283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    }
1284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    printf("application-label-%s:'%s'\n", localeStr,
12852675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                           ResTable::normalizeForOutput(llabel.string()).string());
1286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResTable_config tmpConfig = config;
1291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t ND = densities.size();
1292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<ND; i++) {
1293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            tmpConfig.density = densities[i];
1294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setConfiguration(tmpConfig);
1295ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR,
1296ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    &error);
1297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (icon != "") {
12982675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                printf("application-icon-%d:'%s'\n", densities[i],
12992675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(icon.string()).string());
1300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        assets.setConfiguration(config);
1303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1304ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR, &error);
1305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1306ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
1307ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    error.string());
1308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1310ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        int32_t testOnly = AaptXml::getIntegerAttribute(tree, TEST_ONLY_ATTR, 0,
1311ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                &error);
1312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1313ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n",
1314ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    error.string());
1315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1317d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn
13185f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
13195f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                                                       &error);
1320d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                        if (error != "") {
1321d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                            fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
1322d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                                    error.string());
1323d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                            goto bail;
1324d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                        }
13252675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        printf("application: label='%s' ",
13262675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                ResTable::normalizeForOutput(label.string()).string());
1327d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                        printf("icon='%s'", ResTable::normalizeForOutput(icon.string()).string());
1328d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                        if (banner != "") {
13295f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            printf(" banner='%s'",
13305f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                   ResTable::normalizeForOutput(banner.string()).string());
1331d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                        }
1332d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                        printf("\n");
1333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (testOnly != 0) {
1334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("testOnly='%d'\n", testOnly);
1335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1337d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                        int32_t isGame = AaptXml::getResolvedIntegerAttribute(res, tree,
1338d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                                ISGAME_ATTR, 0, &error);
1339d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                        if (error != "") {
1340d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                            fprintf(stderr, "ERROR getting 'android:isGame' attribute: %s\n",
1341d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                                    error.string());
1342d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                            goto bail;
1343d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                        }
1344d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                        if (isGame != 0) {
1345d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                            printf("application-isGame\n");
1346d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn                        }
1347d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn
1348ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        int32_t debuggable = AaptXml::getResolvedIntegerAttribute(res, tree,
1349ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                DEBUGGABLE_ATTR, 0, &error);
1350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1351ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n",
1352ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    error.string());
1353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (debuggable != 0) {
1356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("application-debuggable\n");
1357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1358e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
1359e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // We must search by name because the multiArch flag hasn't been API
1360e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // frozen yet.
1361e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        int32_t multiArchIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
1362e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                "multiArch");
1363e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (multiArchIndex >= 0) {
1364e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            Res_value value;
1365e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            if (tree.getAttributeValue(multiArchIndex, &value) != NO_ERROR) {
1366e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                if (value.dataType >= Res_value::TYPE_FIRST_INT &&
1367e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                        value.dataType <= Res_value::TYPE_LAST_INT) {
1368e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                    hasMultiArch = value.data;
1369e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                }
1370e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            }
1371e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
1372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-sdk") {
13735f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        int32_t code = AaptXml::getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR,
13745f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                                                    &error);
1375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
1377ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            String8 name = AaptXml::getResolvedAttribute(res, tree,
1378ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    MIN_SDK_VERSION_ATTR, &error);
1379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
13805f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                fprintf(stderr,
13815f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "ERROR getting 'android:minSdkVersion' attribute: %s\n",
1382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
1383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut") targetSdk = 4;
13862675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("sdkVersion:'%s'\n",
13872675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
1389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            targetSdk = code;
1390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("sdkVersion:'%d'\n", code);
1391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1392ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        code = AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR);
1393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (code != -1) {
1394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("maxSdkVersion:'%d'\n", code);
1395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1396ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        code = AaptXml::getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
1397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
1399ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            String8 name = AaptXml::getResolvedAttribute(res, tree,
1400ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    TARGET_SDK_VERSION_ATTR, &error);
1401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
14025f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                fprintf(stderr,
14035f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
1404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
1405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
14082675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("targetSdkVersion:'%s'\n",
14092675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
1411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (targetSdk < code) {
1412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                targetSdk = code;
1413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("targetSdkVersion:'%d'\n", code);
1415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-configuration") {
1417ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        int32_t reqTouchScreen = AaptXml::getIntegerAttribute(tree,
1418ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                REQ_TOUCH_SCREEN_ATTR, 0);
1419ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        int32_t reqKeyboardType = AaptXml::getIntegerAttribute(tree,
1420ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                REQ_KEYBOARD_TYPE_ATTR, 0);
1421ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        int32_t reqHardKeyboard = AaptXml::getIntegerAttribute(tree,
1422ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                REQ_HARD_KEYBOARD_ATTR, 0);
1423ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        int32_t reqNavigation = AaptXml::getIntegerAttribute(tree,
1424ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                REQ_NAVIGATION_ATTR, 0);
1425ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        int32_t reqFiveWayNav = AaptXml::getIntegerAttribute(tree,
1426ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                REQ_FIVE_WAY_NAV_ATTR, 0);
1427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("uses-configuration:");
1428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqTouchScreen != 0) {
1429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqTouchScreen='%d'", reqTouchScreen);
1430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqKeyboardType != 0) {
1432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqKeyboardType='%d'", reqKeyboardType);
1433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqHardKeyboard != 0) {
1435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqHardKeyboard='%d'", reqHardKeyboard);
1436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqNavigation != 0) {
1438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqNavigation='%d'", reqNavigation);
1439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqFiveWayNav != 0) {
1441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqFiveWayNav='%d'", reqFiveWayNav);
1442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("\n");
1444ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    } else if (tag == "supports-input") {
1445ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = true;
1446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-screens") {
1447ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        smallScreen = AaptXml::getIntegerAttribute(tree,
1448ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                SMALL_SCREEN_ATTR, 1);
1449ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        normalScreen = AaptXml::getIntegerAttribute(tree,
1450ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                NORMAL_SCREEN_ATTR, 1);
1451ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        largeScreen = AaptXml::getIntegerAttribute(tree,
1452ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                LARGE_SCREEN_ATTR, 1);
1453ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        xlargeScreen = AaptXml::getIntegerAttribute(tree,
1454ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                XLARGE_SCREEN_ATTR, 1);
1455ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        anyDensity = AaptXml::getIntegerAttribute(tree,
1456ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                ANY_DENSITY_ATTR, 1);
1457ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        requiresSmallestWidthDp = AaptXml::getIntegerAttribute(tree,
1458ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                REQUIRES_SMALLEST_WIDTH_DP_ATTR, 0);
1459ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        compatibleWidthLimitDp = AaptXml::getIntegerAttribute(tree,
1460ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                COMPATIBLE_WIDTH_LIMIT_DP_ATTR, 0);
1461ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        largestWidthLimitDp = AaptXml::getIntegerAttribute(tree,
1462ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                LARGEST_WIDTH_LIMIT_DP_ATTR, 0);
14632c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    } else if (tag == "feature-group") {
14642c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        withinFeatureGroup = true;
14652c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        FeatureGroup group;
1466ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        group.label = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR, &error);
14672c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        if (error != "") {
14682c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:label' attribute:"
14692c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    " %s\n", error.string());
14702c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            goto bail;
14712c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
14722c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        featureGroups.add(group);
14732c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-feature") {
1475ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1477694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            const char* androidSchema =
1478694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                    "http://schemas.android.com/apk/res/android";
1479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1480694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            int32_t req = AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1,
1481694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                                                       &error);
1482694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            if (error != "") {
1483694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                SourcePos(manifestFile, tree.getLineNumber()).error(
1484694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                        "failed to read attribute 'android:required': %s",
1485694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                        error.string());
1486694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                goto bail;
1487694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            }
1488694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
1489694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            int32_t version = AaptXml::getIntegerAttribute(tree, androidSchema,
1490694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                                                           "version", 0, &error);
1491694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            if (error != "") {
1492694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                SourcePos(manifestFile, tree.getLineNumber()).error(
1493694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                        "failed to read attribute 'android:version': %s",
1494694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                        error.string());
1495694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                goto bail;
1496694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            }
1497694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
1498694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            commonFeatures.features.add(name, Feature(req != 0, version));
14992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            if (req) {
15002c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addParentFeatures(&commonFeatures, name);
1501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1503ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            int vers = AaptXml::getIntegerAttribute(tree,
1504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    GL_ES_VERSION_ATTR, &error);
1505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error == "") {
1506d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                if (vers > commonFeatures.openGLESVersion) {
1507d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    commonFeatures.openGLESVersion = vers;
1508d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                }
1509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-permission") {
1512ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
15135f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        if (error != "") {
15145f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
15155f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                    error.string());
15165f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            goto bail;
15175f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        }
151858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
15195f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        if (name == "") {
15205f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            fprintf(stderr, "ERROR: missing 'android:name' for uses-permission\n");
15215f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            goto bail;
15225f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        }
15235f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
15245f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, false);
15255f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
15265f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
15275f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            hasWriteExternalStoragePermission = true;
15285f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
15295f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            hasReadExternalStoragePermission = true;
15305f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        } else if (name == "android.permission.READ_PHONE_STATE") {
15315f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            hasReadPhoneStatePermission = true;
15325f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        } else if (name == "android.permission.READ_CONTACTS") {
15335f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            hasReadContactsPermission = true;
15345f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        } else if (name == "android.permission.WRITE_CONTACTS") {
15355f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            hasWriteContactsPermission = true;
15365f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        } else if (name == "android.permission.READ_CALL_LOG") {
15375f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            hasReadCallLogPermission = true;
15385f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        } else if (name == "android.permission.WRITE_CALL_LOG") {
15395f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            hasWriteCallLogPermission = true;
15405f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        }
15415f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
15425f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        printUsesPermission(name,
15435f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
15445f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
15455f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
15465f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                    } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
15475f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
15485f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        if (error != "") {
1549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
15535f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
15545f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        if (name == "") {
15555f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            fprintf(stderr, "ERROR: missing 'android:name' for "
15565f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                    "uses-permission-sdk-23\n");
15575f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            goto bail;
15585f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        }
15595f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
15605f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, true);
15615f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
15625f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                        printUsesPermissionSdk23(
15635f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                name, AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
15645f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
1565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-package") {
1566ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
15682675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("uses-package:'%s'\n",
15692675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "original-package") {
1576ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
15782675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("original-package:'%s'\n",
15792675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-gl-texture") {
1586ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
15882675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("supports-gl-texture:'%s'\n",
15892675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "compatible-screens") {
15969cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        printCompatibleScreens(tree, &error);
15979cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        if (error != "") {
15989cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                            fprintf(stderr, "ERROR getting compatible screens: %s\n",
15999cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                                    error.string());
16009cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                            goto bail;
16019cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        }
1602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        depth--;
1603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "package-verifier") {
1604ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
16065f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            String8 publicKey = AaptXml::getAttribute(tree, PUBLIC_KEY_ATTR,
16075f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                                                      &error);
1608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (publicKey != "" && error == "") {
1609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                printf("package-verifier: name='%s' publicKey='%s'\n",
16102675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(name.string()).string(),
16112675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(publicKey.string()).string());
1612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1615ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                } else if (depth == 3) {
1616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinActivity = false;
1617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinReceiver = false;
1618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinService = false;
16199d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    withinProvider = false;
1620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasIntentFilter = false;
162194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasMetaHostPaymentCategory = false;
162294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasMetaOffHostPaymentCategory = false;
162394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindDeviceAdminPermission = false;
162494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindInputMethodPermission = false;
162594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindAccessibilityServicePermission = false;
162694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindPrintServicePermission = false;
162794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindNfcServicePermission = false;
16289d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    hasRequiredSafAttributes = false;
16299d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    hasBindNotificationListenerServicePermission = false;
1630eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                    hasBindDreamServicePermission = false;
1631ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    if (withinApplication) {
1632ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if(tag == "activity") {
1633ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinActivity = true;
1634ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            activityName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1635ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1636ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1637ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1638ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1639ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1641ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            activityLabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
1642ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    &error);
1643ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1644ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
1645ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1646ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1647ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1649ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            activityIcon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR,
1650ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    &error);
1651ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1652ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
1653ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1654ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1655ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1657ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            activityBanner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
1658ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    &error);
16590a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (error != "") {
16600a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
16610a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                        error.string());
16620a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                goto bail;
16630a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            }
16640a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn
1665ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            int32_t orien = AaptXml::getResolvedIntegerAttribute(res, tree,
1666ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    SCREEN_ORIENTATION_ATTR, &error);
1667ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error == "") {
1668ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (orien == 0 || orien == 6 || orien == 8) {
1669ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests landscape, sensorLandscape, or reverseLandscape.
167043158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                                    addImpliedFeature(
167143158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                                            &impliedFeatures, "android.hardware.screen.landscape",
167243158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                                            String8("one or more activities have specified a "
167343158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                                                    "landscape orientation"),
167443158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                                            false);
1675ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else if (orien == 1 || orien == 7 || orien == 9) {
1676ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests portrait, sensorPortrait, or reversePortrait.
167743158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                                    addImpliedFeature(
167843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                                            &impliedFeatures, "android.hardware.screen.portrait",
167943158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                                            String8("one or more activities have specified a "
168043158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                                                    "portrait orientation"),
168143158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                                            false);
1682ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1684ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "uses-library") {
1685ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            String8 libraryName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1686ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1687ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1688ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for uses-library"
1689ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1690ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1691ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1692ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            int req = AaptXml::getIntegerAttribute(tree,
1693ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    REQUIRED_ATTR, 1);
1694ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("uses-library%s:'%s'\n",
16952675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    req ? "" : "-not-required", ResTable::normalizeForOutput(
16962675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                            libraryName.string()).string());
1697ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "receiver") {
1698ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinReceiver = true;
1699ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            receiverName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1701ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1702ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1703ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for receiver:"
1704ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1705ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1706ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1707a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1708ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR,
1709ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    &error);
1710a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1711a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_DEVICE_ADMIN") {
1712a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindDeviceAdminPermission = true;
1713a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1714a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
17155f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                fprintf(stderr,
17165f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "ERROR getting 'android:permission' attribute for"
17175f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        " receiver '%s': %s\n",
17185f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        receiverName.string(), error.string());
1719a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
1720ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "service") {
1721ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinService = true;
1722ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            serviceName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1724ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1725ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1726ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "service:%s\n", error.string());
1727ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1728ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1729a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1730ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR,
1731ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    &error);
1732a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1733a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_INPUT_METHOD") {
1734a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindInputMethodPermission = true;
17355f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                } else if (permission ==
17365f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "android.permission.BIND_ACCESSIBILITY_SERVICE") {
1737a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindAccessibilityServicePermission = true;
17385f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                } else if (permission ==
17395f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "android.permission.BIND_PRINT_SERVICE") {
1740a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindPrintServicePermission = true;
17415f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                } else if (permission ==
17425f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "android.permission.BIND_NFC_SERVICE") {
174394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasBindNfcServicePermission = true;
17445f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                } else if (permission ==
17455f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
17469d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                    hasBindNotificationListenerServicePermission = true;
1747eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                } else if (permission == "android.permission.BIND_DREAM_SERVICE") {
1748eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                    hasBindDreamServicePermission = true;
1749a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1750a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
17515f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for "
17525f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "service '%s': %s\n", serviceName.string(), error.string());
1753a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
17549d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        } else if (tag == "provider") {
17559d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            withinProvider = true;
17569d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
1757ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            bool exported = AaptXml::getResolvedIntegerAttribute(res, tree,
1758ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    EXPORTED_ATTR, &error);
17599d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
17605f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                fprintf(stderr,
17615f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "ERROR getting 'android:exported' attribute for provider:"
17629d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        " %s\n", error.string());
17639d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
17649d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
17659d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
1766ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            bool grantUriPermissions = AaptXml::getResolvedIntegerAttribute(
1767ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    res, tree, GRANT_URI_PERMISSIONS_ATTR, &error);
17689d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
17695f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                fprintf(stderr,
17705f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "ERROR getting 'android:grantUriPermissions' attribute for "
17715f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "provider: %s\n", error.string());
17729d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
17739d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
17749d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
1775ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            String8 permission = AaptXml::getResolvedAttribute(res, tree,
1776ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    PERMISSION_ATTR, &error);
17779d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
17785f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for "
17795f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "provider: %s\n", error.string());
17809d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
17819d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
17829d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
17839d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            hasRequiredSafAttributes |= exported && grantUriPermissions &&
17849d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                permission == "android.permission.MANAGE_DOCUMENTS";
17859d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
1786ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
1787ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            String8 metaDataName = AaptXml::getResolvedAttribute(res, tree,
1788ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    NAME_ATTR, &error);
1789ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1790ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1791ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "meta-data:%s\n", error.string());
1792ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1793ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
17942675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("meta-data: name='%s' ",
17952675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(metaDataName.string()).string());
1796ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            printResolvedResourceAttribute(res, tree, VALUE_ATTR, String8("value"),
179776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                    &error);
1798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
179976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                // Try looking for a RESOURCE_ATTR
180076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                error = "";
1801ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                printResolvedResourceAttribute(res, tree, RESOURCE_ATTR,
180276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                        String8("resource"), &error);
1803ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (error != "") {
180476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                    fprintf(stderr, "ERROR getting 'android:value' or "
180576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                            "'android:resource' attribute for "
180676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                            "meta-data:%s\n", error.string());
1807ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    goto bail;
1808ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1809ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
181076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                            printf("\n");
1811ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (withinSupportsInput && tag == "input-type") {
1812ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1813ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (name != "" && error == "") {
1814ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                supportedInput.add(name);
1815ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            } else {
1816ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1817ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
18212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    } else if (withinFeatureGroup && tag == "uses-feature") {
1822694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                        const String8 androidSchema("http://schemas.android.com/apk/res/android");
1823d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        FeatureGroup& top = featureGroups.editTop();
1824d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
1825ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        String8 name = AaptXml::getResolvedAttribute(res, tree, NAME_ATTR, &error);
1826d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        if (name != "" && error == "") {
1827694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            Feature feature(true);
1828694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
1829694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            int32_t featureVers = AaptXml::getIntegerAttribute(
1830694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                    tree, androidSchema.string(), "version", 0, &error);
1831694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            if (error == "") {
1832694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                feature.version = featureVers;
1833694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            } else {
1834694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                SourcePos(manifestFile, tree.getLineNumber()).error(
1835694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                        "failed to read attribute 'android:version': %s",
1836694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                        error.string());
1837694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                                goto bail;
1838694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            }
1839694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
1840694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski                            top.features.add(name, feature);
1841d3edfde51bd069a63e820282421d1a534fcf00ceAdam Lesinski                            addParentFeatures(&top, name);
1842694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
1843d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        } else {
1844ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            int vers = AaptXml::getIntegerAttribute(tree, GL_ES_VERSION_ATTR,
1845ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    &error);
1846d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            if (error == "") {
1847d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                if (vers > top.openGLESVersion) {
1848d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    top.openGLESVersion = vers;
1849d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                }
1850d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            }
18512c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
1852a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
185394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                } else if (depth == 4) {
185494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (tag == "intent-filter") {
185594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        hasIntentFilter = true;
185694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        withinIntentFilter = true;
185794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actMainActivity = false;
185894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actWidgetReceivers = false;
185994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actImeService = false;
186094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actWallpaperService = false;
186194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actAccessibilityService = false;
186294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actPrintService = false;
186394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actDeviceAdminEnabled = false;
186494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actHostApduService = false;
186594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actOffHostApduService = false;
18669d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actDocumentsProvider = false;
18679d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actNotificationListenerService = false;
1868eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                        actDreamService = false;
18699d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actCamera = false;
18709d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actCameraSecure = false;
18719d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        catLauncher = false;
187294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    } else if (withinService && tag == "meta-data") {
1873ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
187494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (error != "") {
18755f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute for "
18765f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                    "meta-data tag in service '%s': %s\n", serviceName.string(),
18775f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                    error.string());
187894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            goto bail;
187994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        }
188094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
188194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (name == "android.nfc.cardemulation.host_apdu_service" ||
188294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                name == "android.nfc.cardemulation.off_host_apdu_service") {
188394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            bool offHost = true;
188494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (name == "android.nfc.cardemulation.host_apdu_service") {
188594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                offHost = false;
188694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
188794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
1888ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            String8 xmlPath = AaptXml::getResolvedAttribute(res, tree,
1889ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                                    RESOURCE_ATTR, &error);
189094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (error != "") {
18915f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:resource' attribute for "
18925f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        "meta-data tag in service '%s': %s\n",
18935f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                        serviceName.string(), error.string());
189494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                goto bail;
189594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
189694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
189794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
189894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    offHost, &error);
189994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (error != "") {
190094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                fprintf(stderr, "ERROR getting AID category for service '%s'\n",
190194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        serviceName.string());
190294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                goto bail;
190394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
190494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
190594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            const size_t catLen = categories.size();
190694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            for (size_t i = 0; i < catLen; i++) {
190794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                bool paymentCategory = (categories[i] == "payment");
190894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                if (offHost) {
190994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasMetaOffHostPaymentCategory |= paymentCategory;
191094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                } else {
191194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasMetaHostPaymentCategory |= paymentCategory;
191294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                }
191394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
191494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        }
191594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
1916a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                } else if ((depth == 5) && withinIntentFilter) {
1917a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    String8 action;
1918a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "action") {
1919ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        action = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1920a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1921a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1922a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1923a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1924a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1925a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1926a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1927a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.intent.action.MAIN") {
1928a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isMainActivity = true;
1929a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actMainActivity = true;
19309d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (action == "android.media.action.STILL_IMAGE_CAMERA" ||
19319d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                    action == "android.media.action.VIDEO_CAMERA") {
19329d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actCamera = true;
19339d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (action == "android.media.action.STILL_IMAGE_CAMERA_SECURE") {
19349d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actCameraSecure = true;
1935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1936a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinReceiver) {
1937a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
1938a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWidgetReceivers = true;
1939a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
1940a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actDeviceAdminEnabled = true;
1941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1942a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinService) {
1943a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.view.InputMethod") {
1944a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actImeService = true;
1945a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.service.wallpaper.WallpaperService") {
1946a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWallpaperService = true;
19475f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            } else if (action ==
19485f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                    "android.accessibilityservice.AccessibilityService") {
1949a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actAccessibilityService = true;
19505f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            } else if (action =="android.printservice.PrintService") {
1951a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actPrintService = true;
19525f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            } else if (action ==
19535f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                    "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
195494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                actHostApduService = true;
19555f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            } else if (action ==
19565f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                    "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
195794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                actOffHostApduService = true;
19585f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                            } else if (action ==
19595f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                    "android.service.notification.NotificationListenerService") {
19609d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actNotificationListenerService = true;
1961eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                            } else if (action == "android.service.dreams.DreamService") {
1962eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                actDreamService = true;
19639d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
19649d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        } else if (withinProvider) {
19659d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (action == "android.content.action.DOCUMENTS_PROVIDER") {
19669d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actDocumentsProvider = true;
1967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1969a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (action == "android.intent.action.SEARCH") {
1970a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            isSearchable = true;
1971a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1972a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
1973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1974a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "category") {
1975ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                        String8 category = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1976a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1977a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'name' attribute: %s\n",
1978a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1979a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1980a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1981a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1982a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (category == "android.intent.category.LAUNCHER") {
1983a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isLauncherActivity = true;
19840a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            } else if (category == "android.intent.category.LEANBACK_LAUNCHER") {
19850a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                isLeanbackLauncherActivity = true;
19869d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (category == "android.intent.category.HOME") {
19879d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                catLauncher = true;
1988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-1.6 implicitly granted permission compatibility logic
1995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 4) {
1996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteExternalStoragePermission) {
199758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
199858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
199958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 4"));
2000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasWriteExternalStoragePermission = true;
2001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadPhoneStatePermission) {
200358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.READ_PHONE_STATE"));
200458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"),
200558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 4"));
2006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If the application has requested WRITE_EXTERNAL_STORAGE, we will
2010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // force them to always take READ_EXTERNAL_STORAGE as well.  We always
2011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // do this (regardless of target API version) because we can't have
2012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // an app with write permission but not read permission.
2013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
201458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"));
201558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
201658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                        String8("requested WRITE_EXTERNAL_STORAGE"));
2017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-JellyBean call log permission compatibility.
2020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 16) {
2021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadCallLogPermission && hasReadContactsPermission) {
202258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.READ_CALL_LOG"));
202358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
202458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 16 and requested READ_CONTACTS"));
2025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
202758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.WRITE_CALL_LOG"));
202858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"),
202958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 16 and requested WRITE_CONTACTS"));
2030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2033ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski            // If the app hasn't declared the touchscreen as a feature requirement (either
2034ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski            // directly or implied, required or not), then the faketouch feature is implied.
2035ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski            if (!hasFeature("android.hardware.touchscreen", commonFeatures, impliedFeatures)) {
2036ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski                addImpliedFeature(&impliedFeatures, "android.hardware.faketouch",
203743158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                                  String8("default feature for all apps"), false);
2038ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski            }
20392c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
20402c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            const size_t numFeatureGroups = featureGroups.size();
20412c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            if (numFeatureGroups == 0) {
20422c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                // If no <feature-group> tags were defined, apply auto-implied features.
20435f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                printDefaultFeatureGroup(commonFeatures, impliedFeatures);
20442c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
20452c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            } else {
20462c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                // <feature-group> tags are defined, so we ignore implied features and
20472c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                for (size_t i = 0; i < numFeatureGroups; i++) {
20482c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    FeatureGroup& grp = featureGroups.editItemAt(i);
20492c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
2050d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                    if (commonFeatures.openGLESVersion > grp.openGLESVersion) {
2051d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        grp.openGLESVersion = commonFeatures.openGLESVersion;
2052d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                    }
2053d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
20542c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    // Merge the features defined in the top level (not inside a <feature-group>)
20552c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    // with this feature group.
20562c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    const size_t numCommonFeatures = commonFeatures.features.size();
20572c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    for (size_t j = 0; j < numCommonFeatures; j++) {
20582c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) {
2059d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            grp.features.add(commonFeatures.features.keyAt(j),
2060d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    commonFeatures.features[j]);
20612c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
2062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
206473a05114b051c6dcf5e5126ac94eaf8cac0ab289Adam Lesinski                    if (!grp.features.isEmpty()) {
20652c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        printFeatureGroup(grp);
20662c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    }
2067282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2069282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
20702c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
2071282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWidgetReceivers) {
20729d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("app-widget");
2073282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2074a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasDeviceAdminReceiver) {
20759d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("device-admin");
2076a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
2077282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasImeService) {
20789d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("ime");
2079282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWallpaperService) {
20819d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("wallpaper");
2082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2083a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasAccessibilityService) {
20849d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("accessibility");
2085a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
2086a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasPrintService) {
20879d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("print-service");
2088a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
208994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (hasPaymentService) {
20909d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("payment");
20919d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
20929d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (isSearchable) {
20939d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("search");
20949d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
20959d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasDocumentsProvider) {
20969d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("document-provider");
20979d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
20989d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasLauncher) {
20999d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("launcher");
21009d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
21019d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasNotificationListenerService) {
21029d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("notification-listener");
21039d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
2104eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            if (hasDreamService) {
2105eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                printComponentPresence("dream");
2106eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            }
21079d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasCameraActivity) {
21089d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("camera");
21099d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
21109d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasCameraSecureActivity) {
21119d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("camera-secure");
21129d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
21139d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
21149d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasMainActivity) {
21159d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printf("main\n");
211694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
2117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherActivities) {
2118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-activities\n");
2119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
21209d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski             if (hasOtherReceivers) {
2121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-receivers\n");
2122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherServices) {
2124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-services\n");
2125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // For modern apps, if screen size buckets haven't been specified
2128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // but the new width ranges have, then infer the buckets from them.
2129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
2130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    && requiresSmallestWidthDp > 0) {
2131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int compatWidth = compatibleWidthLimitDp;
2132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (compatWidth <= 0) {
2133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    compatWidth = requiresSmallestWidthDp;
2134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
2136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = -1;
2137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
2138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = 0;
2139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
2141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = -1;
2142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
2143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = 0;
2144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
2146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = -1;
2147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
2148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = 0;
2149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
2151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = -1;
2152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
2153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = 0;
2154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Determine default values for any unspecified screen sizes,
2158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // based on the target SDK of the package.  As of 4 (donut)
2159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // the screen size support was introduced, so all default to
2160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // enabled.
2161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0) {
2162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                smallScreen = targetSdk >= 4 ? -1 : 0;
2163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen > 0) {
2165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                normalScreen = -1;
2166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen > 0) {
2168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                largeScreen = targetSdk >= 4 ? -1 : 0;
2169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen > 0) {
2171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Introduced in Gingerbread.
2172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                xlargeScreen = targetSdk >= 9 ? -1 : 0;
2173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (anyDensity > 0) {
2175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
2176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        || compatibleWidthLimitDp > 0) ? -1 : 0;
2177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-screens:");
2179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen != 0) {
2180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'small'");
2181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen != 0) {
2183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'normal'");
2184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen != 0) {
2186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'large'");
2187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen != 0) {
2189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'xlarge'");
2190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
2193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (requiresSmallestWidthDp > 0) {
2194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
2195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (compatibleWidthLimitDp > 0) {
2197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
2198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largestWidthLimitDp > 0) {
2200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
2201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("locales:");
2204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NL = locales.size();
2205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NL; i++) {
2206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const char* localeStr =  locales[i].string();
2207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (localeStr == NULL || strlen(localeStr) == 0) {
2208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    localeStr = "--_--";
2209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'", localeStr);
2211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("densities:");
2215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t ND = densities.size();
2216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<ND; i++) {
2217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%d'", densities[i]);
2218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
2222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (dir != NULL) {
2223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dir->getFileCount() > 0) {
2224e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    SortedVector<String8> architectures;
2225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    for (size_t i=0; i<dir->getFileCount(); i++) {
2226e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        architectures.add(ResTable::normalizeForOutput(
2227e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                dir->getFileName(i).string()));
2228e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    }
2229e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2230e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    bool outputAltNativeCode = false;
2231e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // A multiArch package is one that contains 64-bit and
2232e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 32-bit versions of native code and expects 3rd-party
2233e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // apps to load these native code libraries. Since most
2234e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 64-bit systems also support 32-bit apps, the apps
2235e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // loading this multiArch package's code may be either
2236e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 32-bit or 64-bit.
2237e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    if (hasMultiArch) {
2238e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // If this is a multiArch package, report the 64-bit
2239e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // version only. Then as a separate entry, report the
2240e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // rest.
2241e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        //
2242e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // If we report the 32-bit architecture, this APK will
2243e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // be installed on a 32-bit device, causing a large waste
2244e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // of bandwidth and disk space. This assumes that
2245e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // the developer of the multiArch package has also
2246e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // made a version that is 32-bit only.
2247e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        String8 intel64("x86_64");
2248e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        String8 arm64("arm64-v8a");
2249e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        ssize_t index = architectures.indexOf(intel64);
2250e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (index < 0) {
2251e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            index = architectures.indexOf(arm64);
2252e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2253e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2254e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (index >= 0) {
2255e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf("native-code: '%s'\n", architectures[index].string());
2256e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            architectures.removeAt(index);
2257e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            outputAltNativeCode = true;
2258e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2259e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    }
2260e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2261e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    const size_t archCount = architectures.size();
2262e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    if (archCount > 0) {
2263e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (outputAltNativeCode) {
2264e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf("alt-");
2265e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2266e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        printf("native-code:");
2267e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        for (size_t i = 0; i < archCount; i++) {
2268e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf(" '%s'", architectures[i].string());
2269e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2270e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        printf("\n");
2271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                delete dir;
2274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badger", option) == 0) {
2276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s", CONSOLE_DATA);
2277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("configurations", option) == 0) {
2278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
2279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
2280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = configs.size();
2281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<N; i++) {
2282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("%s\n", configs[i].toString().string());
2283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
2286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
2291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (asset) {
2294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete asset;
2295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "add" command, which wants to add files to a new or
2302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * pre-existing archive.
2303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doAdd(Bundle* bundle)
2305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
2307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
2308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
2309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getUpdate()) {
2311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* avoid confusion */
2312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: can't use '-u' with add\n");
2313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
2317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
2318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
2321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
2323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
2324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, true);
2328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
2329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
2330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
2335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
2337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s'... (from gzip)\n", fileName);
2338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
2339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (bundle->getJunkPath()) {
2341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 storageName = String8(fileName).getPathLeaf();
23422675f769673f69b0661ddee346292f25cb30a296Maurice Chu                printf(" '%s' as '%s'...\n", fileName,
23432675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        ResTable::normalizeForOutput(storageName.string()).string());
2344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, storageName.string(),
2345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  bundle->getCompressionMethod(), NULL);
2346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
2347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'...\n", fileName);
2348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
2349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
2352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
2353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (result == NAME_NOT_FOUND) {
2354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": file not found\n");
2355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (result == ALREADY_EXISTS) {
2356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": already exists in archive\n");
2357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
2358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "\n");
2359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
2365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
2368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Delete files from an existing archive.
2374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doRemove(Bundle* bundle)
2376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
2378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
2379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
2380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
2382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
2383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
2386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
2388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
2389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, false);
2393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
2394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
2395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zipFileName);
2396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
2401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ZipEntry* entry;
2402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByName(fileName);
2404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (entry == NULL) {
2405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s' NOT FOUND\n", fileName);
2406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
2407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = zip->remove(entry);
2410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
2412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to delete '%s' from '%s'\n",
2413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                bundle->getFileSpecEntry(i), zipFileName);
2414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* update the archive */
2419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip->flush();
2420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
2423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
24263921e87e6e67a063caa1987937d7944b24aef489Adam Lesinskistatic status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
2427fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    const size_t numDirs = dir->getDirs().size();
2428fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    for (size_t i = 0; i < numDirs; i++) {
24293921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        bool ignore = ignoreConfig;
24303921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
24313921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        const char* dirStr = subDir->getLeaf().string();
24323921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
24333921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            ignore = true;
24343921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        }
24353921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        status_t err = addResourcesToBuilder(subDir, builder, ignore);
2436fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        if (err != NO_ERROR) {
2437fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            return err;
2438fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2439fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2440fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2441fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    const size_t numFiles = dir->getFiles().size();
2442fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    for (size_t i = 0; i < numFiles; i++) {
2443fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        sp<AaptGroup> gp = dir->getFiles().valueAt(i);
2444fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numConfigs = gp->getFiles().size();
2445fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t j = 0; j < numConfigs; j++) {
24463921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            status_t err = NO_ERROR;
24473921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            if (ignoreConfig) {
24483921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski                err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
24493921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            } else {
24503921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski                err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
24513921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            }
2452fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2453fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "Failed to add %s (%s) to builder.\n",
2454fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                        gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
2455fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                return err;
2456fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2457fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2458fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2459fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    return NO_ERROR;
2460fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski}
2461fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2462fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinskistatic String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
2463fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (split->isBase()) {
2464fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        return original;
2465fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2466fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2467fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    String8 ext(original.getPathExtension());
2468fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (ext == String8(".apk")) {
2469fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        return String8::format("%s_%s%s",
2470fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                original.getBasePath().string(),
2471fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                split->getDirectorySafeName().string(),
2472fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                ext.string());
2473fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2474fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2475fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    return String8::format("%s_%s", original.string(),
2476fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            split->getDirectorySafeName().string());
2477fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski}
2478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Package up an asset directory and associated application files.
2481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doPackage(Bundle* bundle)
2483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* outputAPKFile;
2485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int retVal = 1;
2486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err;
2487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<AaptAssets> assets;
2488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int N;
2489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    FILE* fp;
2490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 dependencyFile;
2491fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    sp<ApkBuilder> builder;
2492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2493a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin    // -c en_XA or/and ar_XB means do pseudolocalization
2494fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
2495fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    err = configFilter->parse(bundle->getConfigurations());
2496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
2497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2499fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (configFilter->containsPseudo()) {
2500a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
2501a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin    }
2502fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (configFilter->containsPseudoBidi()) {
2503a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
2504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    N = bundle->getFileSpecCount();
2507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
250809384303dea4f3f01d5682918d7bab9bf83a02b1Adam Lesinski            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
2509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no input files\n");
2510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    outputAPKFile = bundle->getOutputAPKFile();
2514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make sure the filenames provided exist and are of the appropriate type.
2516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
2517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        FileType type;
2518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        type = getFileType(outputAPKFile);
2519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
2520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr,
2521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                "ERROR: output file '%s' exists but is not regular file\n",
2522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                outputAPKFile);
2523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Load the assets.
2528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets = new AaptAssets();
2529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Set up the resource gathering in assets if we're going to generate
2531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // dependency files. Every time we encounter a resource while slurping
2532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the tree, we'll add it to these stores so we have full resource paths
2533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // to write to a dependency file.
2534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> resPathStore = new FilePathStore;
2536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullResPaths(resPathStore);
2537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> assetPathStore = new FilePathStore;
2538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullAssetPaths(assetPathStore);
2539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = assets->slurpFromArgs(bundle);
2542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
2543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
2547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->print(String8());
2548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2550fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // Create the ApkBuilder, which will collect the compiled files
2551fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // to write to the final APK (or sets of APKs if we are building
2552fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // a Split APK.
2553fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    builder = new ApkBuilder(configFilter);
2554fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2555fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // If we are generating a Split APK, find out which configurations to split on.
2556fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (bundle->getSplitConfigurations().size() > 0) {
2557fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
2558fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numSplits = splitStrs.size();
2559fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t i = 0; i < numSplits; i++) {
2560fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            std::set<ConfigDescription> configs;
2561fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
2562fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
2563fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2564fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2565fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2566fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            err = builder->createSplitForConfigs(configs);
2567fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2568fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2569fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2570fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2571fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2572fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If they asked for any fileAs that need to be compiled, do so.
2574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
2575fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        err = buildResources(bundle, assets, builder);
2576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != 0) {
2577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // At this point we've read everything and processed everything.  From here
2582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // on out it's just writing output files.
2583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Update symbols with information about which ones are needed as Java symbols.
2588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets->applyJavaSymbols();
2589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, do that here
2594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If this is the packaging step, generate the dependency file next to
2596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the output apk (e.g. bin/resources.ap_.d)
2597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outputAPKFile) {
2598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(outputAPKFile);
2599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Add the .d extension to the dependency file.
2600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.append(".d");
2601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Else if this is the R.java dependency generation step,
2603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // generate the dependency file in the R.java package subdirectory
2604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java.d
2605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(bundle->getRClassDir());
2606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.appendPath("R.java.d");
2607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Make sure we have a clean dependency file to start with
2609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "w");
2610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
2611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out R.java constants
2614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets->havePrivateSymbols()) {
2615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getCustomPackage() == NULL) {
2616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Write the R.java file into the appropriate class directory
2617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java
26181e466385d4a4f1acee080fa0fdf16cc8fd8ce7caAdam Lesinski            err = writeResourceSymbols(bundle, assets, assets->getPackage(), true,
2619a6d7e3fb9c9233b9ae46b702d17433854c43d6a0Tao Bai                    bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const String8 customPkg(bundle->getCustomPackage());
26221e466385d4a4f1acee080fa0fdf16cc8fd8ce7caAdam Lesinski            err = writeResourceSymbols(bundle, assets, customPkg, true,
2623a6d7e3fb9c9233b9ae46b702d17433854c43d6a0Tao Bai                    bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2626282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If we have library files, we're going to write our R.java file into
2629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the appropriate class directory for those libraries as well.
2630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // e.g. gen/com/foo/app/lib/R.java
2631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getExtraPackages() != NULL) {
2632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Split on colon
2633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 libs(bundle->getExtraPackages());
2634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
2635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while (packageString != NULL) {
2636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Write the R.java file out with the correct package name
26370f3a5a6559a955ea20f1ae2d3e0995f3fa821c90Marcin Kosiba                err = writeResourceSymbols(bundle, assets, String8(packageString), true,
2638a6d7e3fb9c9233b9ae46b702d17433854c43d6a0Tao Bai                        bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (err < 0) {
2640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    goto bail;
2641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                packageString = strtok(NULL, ":");
2643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            libs.unlockBuffer();
2645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
26471e466385d4a4f1acee080fa0fdf16cc8fd8ce7caAdam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getPackage(), false, false);
2648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
26511e466385d4a4f1acee080fa0fdf16cc8fd8ce7caAdam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true, false);
2652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out the ProGuard file
2658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = writeProguardFile(bundle, assets);
2659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
2660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2663682583c8902efbd33d4394131a2214ce94469535Rohit Agrawal    // Write out the Main Dex ProGuard file
2664682583c8902efbd33d4394131a2214ce94469535Rohit Agrawal    err = writeMainDexProguardFile(bundle, assets);
2665682583c8902efbd33d4394131a2214ce94469535Rohit Agrawal    if (err < 0) {
2666682583c8902efbd33d4394131a2214ce94469535Rohit Agrawal        goto bail;
2667682583c8902efbd33d4394131a2214ce94469535Rohit Agrawal    }
2668682583c8902efbd33d4394131a2214ce94469535Rohit Agrawal
2669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write the apk
2670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
2671fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        // Gather all resources and add them to the APK Builder. The builder will then
2672fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        // figure out which Split they belong in.
2673fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        err = addResourcesToBuilder(assets, builder);
2674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
2675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2677fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2678fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const Vector<sp<ApkSplit> >& splits = builder->getSplits();
2679fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numSplits = splits.size();
2680fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t i = 0; i < numSplits; i++) {
2681fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            const sp<ApkSplit>& split = splits[i];
2682fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            String8 outputPath = buildApkName(String8(outputAPKFile), split);
2683fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            err = writeAPK(bundle, outputPath, split);
2684fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2685fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
2686fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2687fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2688fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, we need to finish up here.
2692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the writeResourceSymbols and writeAPK functions have already written the target
2693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // half of the dependency file, now we need to write the prerequisites. (files that
2694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the R.java file or .ap_ file depend on)
2695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Now that writeResourceSymbols or writeAPK has taken care of writing
2697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the targets to our dependency file, we'll write the prereqs
2698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "a+");
2699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, " : ");
2700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool includeRaw = (outputAPKFile != NULL);
2701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
2702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Also manually add the AndroidManifeset since it's not under res/ or assets/
2703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // and therefore was not added to our pathstores during slurping
2704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
2705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
2706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    retVal = 0;
2709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        SourcePos::printErrors(stderr);
2712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return retVal;
2714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching
2718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * PRECONDITIONS
2719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -S flag points to a source directory containing drawable* folders
2720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -C flag points to destination directory. The folder structure in the
2721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *     source directory will be mirrored to the destination (cache) directory
2722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
2723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * POSTCONDITIONS
2724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  Destination directory will be updated to match the PNG files in
27252675f769673f69b0661ddee346292f25cb30a296Maurice Chu *  the source directory.
2726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doCrunch(Bundle* bundle)
2728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching PNG Files in ");
2730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
2731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
2732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    updatePreProcessedCache(bundle);
2734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching on a single flag
2740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -i points to a single png file
2741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -o points to a single png output file
2742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doSingleCrunch(Bundle* bundle)
2744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
2746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
2747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 input(bundle->getSingleCrunchInputFile());
2749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 output(bundle->getSingleCrunchOutputFile());
2750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
2752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // we can't return the status_t as it gets truncate to the lower 8 bits.
2753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 42;
2754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
27596f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochezint runInDaemonMode(Bundle* bundle) {
27606f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez    std::cout << "Ready" << std::endl;
2761de3ab0a9e8609f6a631b2c047f352069bb9cfa86Chris Warrington    for (std::string cmd; std::getline(std::cin, cmd);) {
2762de3ab0a9e8609f6a631b2c047f352069bb9cfa86Chris Warrington        if (cmd == "quit") {
27636f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez            return NO_ERROR;
2764de3ab0a9e8609f6a631b2c047f352069bb9cfa86Chris Warrington        } else if (cmd == "s") {
2765de3ab0a9e8609f6a631b2c047f352069bb9cfa86Chris Warrington            // Two argument crunch
2766de3ab0a9e8609f6a631b2c047f352069bb9cfa86Chris Warrington            std::string inputFile, outputFile;
2767de3ab0a9e8609f6a631b2c047f352069bb9cfa86Chris Warrington            std::getline(std::cin, inputFile);
2768de3ab0a9e8609f6a631b2c047f352069bb9cfa86Chris Warrington            std::getline(std::cin, outputFile);
2769de3ab0a9e8609f6a631b2c047f352069bb9cfa86Chris Warrington            bundle->setSingleCrunchInputFile(inputFile.c_str());
2770de3ab0a9e8609f6a631b2c047f352069bb9cfa86Chris Warrington            bundle->setSingleCrunchOutputFile(outputFile.c_str());
2771de3ab0a9e8609f6a631b2c047f352069bb9cfa86Chris Warrington            std::cout << "Crunching " << inputFile << std::endl;
27726f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez            if (doSingleCrunch(bundle) != NO_ERROR) {
27736f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez                std::cout << "Error" << std::endl;
27746f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez            }
27756f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez            std::cout << "Done" << std::endl;
27766f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez        } else {
27776f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez            // in case of invalid command, just bail out.
27786f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez            std::cerr << "Unknown command" << std::endl;
27796f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez            return -1;
27806f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez        }
27816f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez    }
27826f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez    return -1;
27836f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez}
27846f1280cf170b358a57ff70341a9f2ad224e5a662Jerome Dochez
2785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskichar CONSOLE_DATA[2925] = {
2786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
2791282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
2792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
2795282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
2796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
2799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
2802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
2803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2804282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
2806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
2807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
2810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
2813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
2814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
2817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
2820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
2821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
2824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
2825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2826282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2827282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
2828282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
2831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
2832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
2834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
2835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
2837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
2838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
2839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
2842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
2843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
2844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
2846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
2847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
2848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
2849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
2852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
2853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
2854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
2855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
2856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
2857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
2858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
2860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
2862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
2864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
2865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
2867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
2868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
2869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
2872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
2874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
2875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
2878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
2879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
2885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
2886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2888282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2889282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
2890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2892282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
2893282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2894282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2895282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
2896282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
2897282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2898282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2899282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2901282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
2903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
2904282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2905282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2906282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
2907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
2908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
2911282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
2912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
2913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
2914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
2915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
2918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
2919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
2920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
2921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
2922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2924282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2927282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2928282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
2929282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2931282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
2932282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
2933282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2934282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
2936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
2937282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2938282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
2939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
2940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2942282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
2943282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
2944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2945282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2947282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2948282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10
2949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  };
2950