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
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResTable& res = assets.getResources(false);
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (&res == NULL) {
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo resource table found.\n");
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nResource table:\n");
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.print(false);
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                   Asset::ACCESS_BUFFER);
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (manifestAsset == NULL) {
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo AndroidManifest.xml found.\n");
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nAndroid manifest:\n");
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree tree;
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.setTo(manifestAsset->getBuffer(true),
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       manifestAsset->getLength());
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete manifestAsset;
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = 0;
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
249ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinskistatic void printResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree,
25076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        uint32_t attrRes, String8 attrLabel, String8* outError)
25176327314d2238e105f8b94909f9c0cf85caca318Maurice Chu{
25276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    Res_value value;
253ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    AaptXml::getResolvedResourceAttribute(resTable, tree, attrRes, &value, outError);
25476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (*outError != "") {
25576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        *outError = "error print resolved resource attribute";
25676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        return;
25776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
25876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (value.dataType == Res_value::TYPE_STRING) {
259ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        String8 result = AaptXml::getResolvedAttribute(resTable, tree, attrRes, outError);
2602675f769673f69b0661ddee346292f25cb30a296Maurice Chu        printf("%s='%s'", attrLabel.string(),
2612675f769673f69b0661ddee346292f25cb30a296Maurice Chu                ResTable::normalizeForOutput(result.string()).string());
26276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
26376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu            value.dataType <= Res_value::TYPE_LAST_INT) {
26476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='%d'", attrLabel.string(), value.data);
26576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else {
26676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='0x%x'", attrLabel.string(), (int)value.data);
26776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
26876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu}
26976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// These are attribute resource constants for the platform, as found
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// in android.R.attr
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskienum {
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LABEL_ATTR = 0x01010001,
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ICON_ATTR = 0x01010002,
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NAME_ATTR = 0x01010003,
276a5018c900f126ee8424c82497f32983873db741bAdam Lesinski    PERMISSION_ATTR = 0x01010006,
2779d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    EXPORTED_ATTR = 0x01010010,
2789d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
27994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    RESOURCE_ATTR = 0x01010025,
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    DEBUGGABLE_ATTR = 0x0101000f,
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VALUE_ATTR = 0x01010024,
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_CODE_ATTR = 0x0101021b,
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_NAME_ATTR = 0x0101021c,
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_ORIENTATION_ATTR = 0x0101001e,
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MIN_SDK_VERSION_ATTR = 0x0101020c,
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MAX_SDK_VERSION_ATTR = 0x01010271,
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_TOUCH_SCREEN_ATTR = 0x01010227,
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_HARD_KEYBOARD_ATTR = 0x01010229,
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_NAVIGATION_ATTR = 0x0101022a,
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TARGET_SDK_VERSION_ATTR = 0x01010270,
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TEST_ONLY_ATTR = 0x01010272,
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ANY_DENSITY_ATTR = 0x0101026c,
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    GL_ES_VERSION_ATTR = 0x01010281,
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SMALL_SCREEN_ATTR = 0x01010284,
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NORMAL_SCREEN_ATTR = 0x01010285,
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGE_SCREEN_ATTR = 0x01010286,
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    XLARGE_SCREEN_ATTR = 0x010102bf,
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRED_ATTR = 0x0101028e,
301caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski    INSTALL_LOCATION_ATTR = 0x010102b7,
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_SIZE_ATTR = 0x010102ca,
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_DENSITY_ATTR = 0x010102cb,
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    PUBLIC_KEY_ATTR = 0x010103a6,
30894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    CATEGORY_ATTR = 0x010103e8,
3090a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn    BANNER_ATTR = 0x10103f2,
310d9b1cad71e8aaf94e7738d2e47d3a06daa3cdf2dTim Kilbourn    ISGAME_ATTR = 0x10103f4,
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3132675f769673f69b0661ddee346292f25cb30a296Maurice ChuString8 getComponentName(String8 &pkgName, String8 &componentName) {
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = componentName.find(".");
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 retStr(pkgName);
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx == 0) {
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (idx < 0) {
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += ".";
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
3222675f769673f69b0661ddee346292f25cb30a296Maurice Chu        return componentName;
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3242675f769673f69b0661ddee346292f25cb30a296Maurice Chu    return retStr;
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3279cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinskistatic void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResXMLTree::event_code_t code;
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int depth = 0;
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool first = true;
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("compatible-screens:");
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code == ResXMLTree::END_TAG) {
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            depth--;
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (depth < 0) {
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code != ResXMLTree::START_TAG) {
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        depth++;
3459cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        const char16_t* ctag16 = tree.getElementName(&len);
3469cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        if (ctag16 == NULL) {
3479cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            *outError = "failed to get XML element name (bad string pool)";
3489cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            return;
3499cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        }
3509cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        String8 tag(ctag16);
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tag == "screen") {
352ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            int32_t screenSize = AaptXml::getIntegerAttribute(tree,
353ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    SCREEN_SIZE_ATTR);
354ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            int32_t screenDensity = AaptXml::getIntegerAttribute(tree,
355ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    SCREEN_DENSITY_ATTR);
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (screenSize > 0 && screenDensity > 0) {
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!first) {
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf(",");
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                first = false;
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("'%d/%d'", screenSize, screenDensity);
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("\n");
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
36858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
36958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
37058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (maxSdkVersion != -1) {
37158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski         printf(" maxSdkVersion='%d'", maxSdkVersion);
37258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
37358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("\n");
37458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
37558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (optional) {
37658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("optional-permission: name='%s'",
37758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                ResTable::normalizeForOutput(name.string()).string());
37858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        if (maxSdkVersion != -1) {
37958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            printf(" maxSdkVersion='%d'", maxSdkVersion);
38058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        }
38158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("\n");
38258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
38358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
38458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
38558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesImpliedPermission(const String8& name, const String8& reason) {
38658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-implied-permission: name='%s' reason='%s'\n",
38758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(name.string()).string(),
38858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(reason.string()).string());
38958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
39058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
39194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam LesinskiVector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost,
39294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        String8 *outError = NULL)
39394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski{
39494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
39594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    if (aidAsset == NULL) {
39694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (outError != NULL) *outError = "xml resource does not exist";
39794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        return Vector<String8>();
39894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
39994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
40094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
40194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
40294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    bool withinApduService = false;
40394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Vector<String8> categories;
40494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
40594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    String8 error;
40694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree tree;
40794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
40894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
40994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    size_t len;
41094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    int depth = 0;
41194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree::event_code_t code;
41294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
41394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (code == ResXMLTree::END_TAG) {
41494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth--;
4159cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
4169cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
4179cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
4189cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
4199cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
4209cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
42194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
42294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 0 && tag == serviceTagName) {
42394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                withinApduService = false;
42494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
42594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
42694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        } else if (code == ResXMLTree::START_TAG) {
42794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth++;
4289cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
4299cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
4309cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
4319cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
4329cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
4339cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
43494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
43594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 1) {
43694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == serviceTagName) {
43794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    withinApduService = true;
43894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
43994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            } else if (depth == 2 && withinApduService) {
44094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == "aid-group") {
441ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    String8 category = AaptXml::getAttribute(tree, CATEGORY_ATTR, &error);
44294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (error != "") {
44394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (outError != NULL) *outError = error;
44494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        return Vector<String8>();
44594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
44694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
44794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    categories.add(category);
44894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
44994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
45094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        }
45194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
45294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    aidAsset->close();
45394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    return categories;
45494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski}
45594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
4569d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinskistatic void printComponentPresence(const char* componentName) {
4579d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    printf("provides-component:'%s'\n", componentName);
4589d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski}
4599d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
4602c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
4612c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a feature that has been automatically added due to
4622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * a pre-requisite or some other reason.
4632c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
4642c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct ImpliedFeature {
4652c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
4662c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Name of the implied feature.
4672c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
4682c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name;
4692c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
4702c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
4712c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * List of human-readable reasons for why this feature was implied.
4722c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
4732c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    SortedVector<String8> reasons;
4742c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
4752c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
4762c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
4772c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a <feature-group> tag in the AndroidManifest.xml
4782c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
4792c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct FeatureGroup {
480d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    FeatureGroup() : openGLESVersion(-1) {}
481d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
4822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
4832c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Human readable label
4842c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
4852c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 label;
4862c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
4872c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
4882c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Explicit features defined in the group
4892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
4902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    KeyedVector<String8, bool> features;
491d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
492d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    /**
493d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     * OpenGL ES version required
494d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     */
495d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    int openGLESVersion;
4962c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
4972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
4982c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
4992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const char* name, const char* reason) {
5002c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name8(name);
5012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    ssize_t idx = impliedFeatures->indexOfKey(name8);
5022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (idx < 0) {
5032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        idx = impliedFeatures->add(name8, ImpliedFeature());
5042c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        impliedFeatures->editValueAt(idx).name = name8;
5052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
5062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    impliedFeatures->editValueAt(idx).reasons.add(String8(reason));
5072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
5082c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5092c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void printFeatureGroup(const FeatureGroup& grp,
5102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const KeyedVector<String8, ImpliedFeature>* impliedFeatures = NULL) {
5112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    printf("feature-group: label='%s'\n", grp.label.string());
5122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
513d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    if (grp.openGLESVersion > 0) {
514d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        printf("  uses-gl-es: '0x%x'\n", grp.openGLESVersion);
515d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    }
516d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
5172c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numFeatures = grp.features.size();
5182c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numFeatures; i++) {
51973a05114b051c6dcf5e5126ac94eaf8cac0ab289Adam Lesinski        const bool required = grp.features[i];
5202c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const String8& featureName = grp.features.keyAt(i);
52273a05114b051c6dcf5e5126ac94eaf8cac0ab289Adam Lesinski        printf("  uses-feature%s: name='%s'\n", (required ? "" : "-not-required"),
5232c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                ResTable::normalizeForOutput(featureName.string()).string());
5242c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
5252c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5262c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numImpliedFeatures =
5272c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        (impliedFeatures != NULL) ? impliedFeatures->size() : 0;
5282c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numImpliedFeatures; i++) {
5292c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i);
5302c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        if (grp.features.indexOfKey(impliedFeature.name) >= 0) {
5312c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // The feature is explicitly set, no need to use implied
5322c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // definition.
5332c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            continue;
5342c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
5352c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5362c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        String8 printableFeatureName(ResTable::normalizeForOutput(
5372c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    impliedFeature.name.string()));
5382c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("  uses-feature: name='%s'\n", printableFeatureName.string());
5392c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("  uses-implied-feature: name='%s' reason='",
5402c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printableFeatureName.string());
5412c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const size_t numReasons = impliedFeature.reasons.size();
5422c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        for (size_t j = 0; j < numReasons; j++) {
5432c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            printf("%s", impliedFeature.reasons[j].string());
5442c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            if (j + 2 < numReasons) {
5452c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", ");
5462c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            } else if (j + 1 < numReasons) {
5472c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", and ");
5482c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            }
5492c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
5502c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("'\n");
5512c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
5522c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
5532c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5542c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addParentFeatures(FeatureGroup* grp, const String8& name) {
5552c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (name == "android.hardware.camera.autofocus" ||
5562c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.camera.flash") {
5572c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.camera"), true);
5582c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.location.gps" ||
5592c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.location.network") {
5602c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.location"), true);
5612c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch") {
5622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), true);
5632c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
5642c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen.multitouch"), true);
5652c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), true);
566d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    } else if (name == "android.hardware.opengles.aep") {
567d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        const int openGLESVersion31 = 0x00030001;
568d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        if (openGLESVersion31 > grp->openGLESVersion) {
569d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski            grp->openGLESVersion = openGLESVersion31;
570d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        }
5712c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
5722c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
5732c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "dump" command, to extract select data from an archive.
576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiextern char CONSOLE_DATA[2925]; // see EOF
578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doDump(Bundle* bundle)
579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump option specified\n");
584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump file specified\n");
589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* option = bundle->getFileSpecEntry(0);
593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* filename = bundle->getFileSpecEntry(1);
594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    AssetManager assets;
596f85e41f29a0e9313c2d4725f9d9648591ea49f3bNarayan Kamath    int32_t assetsCookie;
597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make a dummy config for retrieving resources...  we need to supply
603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // non-default values for some configs so that we can retrieve resources
604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // in the app that don't have a default.  The most important of these is
605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the API version because key resources like icons will have an implicit
606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // version if they are using newer config types like density.
607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_config config;
60891447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath    memset(&config, 0, sizeof(ResTable_config));
609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[0] = 'e';
610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[1] = 'n';
611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[0] = 'U';
612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[1] = 'S';
613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.orientation = ResTable_config::ORIENTATION_PORT;
614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.density = ResTable_config::DENSITY_MEDIUM;
615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.sdkVersion = 10000; // Very high.
616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenWidthDp = 320;
617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenHeightDp = 480;
618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.smallestScreenWidthDp = 320;
619c2dea8daea2ae0001d56689d96ce1066012b7b40Adam Lesinski    config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL;
620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets.setConfiguration(config);
621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ResTable& res = assets.getResources(false);
623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (&res == NULL) {
624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
62563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        return 1;
62625e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski    } else if (res.getError() != NO_ERROR) {
62725e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
62863e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        return 1;
62963e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    }
63063e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski
6312cb761e3ddb9d68ab430013e9cd15ecaab9fbc62Adam Lesinski    // The dynamicRefTable can be null if there are no resources for this asset cookie.
6322cb761e3ddb9d68ab430013e9cd15ecaab9fbc62Adam Lesinski    // This fine.
63363e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie);
634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
63563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    Asset* asset = NULL;
63663e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski
637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strcmp("resources", option) == 0) {
638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        res.print(bundle->getValues());
640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("strings", option) == 0) {
643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResStringPool* pool = res.getTableStringBlock(0);
644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printStringPool(pool);
645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmltree", option) == 0) {
647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
65463e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            ResXMLTree tree(dynamicRefTable);
65563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.restart();
667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.uninit();
669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmlstrings", option) == 0) {
674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
677282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
679282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
68163e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
682282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
686282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
68763e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            ResXMLTree tree(dynamicRefTable);
688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printStringPool(&tree.getStrings());
694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
69963e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER);
700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (asset == NULL) {
701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
70563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        ResXMLTree tree(dynamicRefTable);
706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.setTo(asset->getBuffer(true),
707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       asset->getLength()) != NO_ERROR) {
708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        tree.restart();
712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcmp("permissions", option) == 0) {
714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
7269cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                const char16_t* ctag16 = tree.getElementName(&len);
7279cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                if (ctag16 == NULL) {
7289cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
7299cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    goto bail;
7309cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                }
7319cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                String8 tag(ctag16);
732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d tag %s\n", depth, tag.string());
733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
738ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
7392675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "permission") {
741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
742ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
7472675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("permission: %s\n",
7482675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(name.string()).string());
749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "uses-permission") {
750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
751ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
75658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(name,
757ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
758ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                            AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
759282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badging", option) == 0) {
762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<String8> locales;
763282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getLocales(&locales);
764282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
765282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
766282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
767282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            SortedVector<int> densities;
768282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NC = configs.size();
769282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NC; i++) {
770282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int dens = configs[i].density;
771282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dens == 0) {
772282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    dens = 160;
773282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                densities.add(dens);
775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
776282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
780282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 error;
781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinActivity = false;
782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isMainActivity = false;
783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isLauncherActivity = false;
7840a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            bool isLeanbackLauncherActivity = false;
785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isSearchable = false;
786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinApplication = false;
787ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            bool withinSupportsInput = false;
7882c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            bool withinFeatureGroup = false;
789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinReceiver = false;
790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinService = false;
7919d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool withinProvider = false;
792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinIntentFilter = false;
793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasMainActivity = false;
794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherActivities = false;
795282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherReceivers = false;
796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherServices = false;
7979d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasIntentFilter = false;
7989d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWallpaperService = false;
800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasImeService = false;
801a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasAccessibilityService = false;
802a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasPrintService = false;
803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWidgetReceivers = false;
804a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasDeviceAdminReceiver = false;
80594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasPaymentService = false;
8069d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasDocumentsProvider = false;
8079d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasCameraActivity = false;
8089d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasCameraSecureActivity = false;
8099d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasLauncher = false;
8109d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasNotificationListenerService = false;
811eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool hasDreamService = false;
8129d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actMainActivity = false;
814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWidgetReceivers = false;
815a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actDeviceAdminEnabled = false;
816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actImeService = false;
817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWallpaperService = false;
818a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actAccessibilityService = false;
819a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actPrintService = false;
82094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actHostApduService = false;
82194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actOffHostApduService = false;
8229d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actDocumentsProvider = false;
8239d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actNotificationListenerService = false;
824eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool actDreamService = false;
8259d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actCamera = false;
8269d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actCameraSecure = false;
8279d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool catLauncher = false;
82894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaHostPaymentCategory = false;
82994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaOffHostPaymentCategory = false;
830a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
831a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // These permissions are required by services implementing services
832a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // the system binds to (IME, Accessibility, PrintServices, etc.)
833a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindDeviceAdminPermission = false;
834a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindInputMethodPermission = false;
835a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindAccessibilityServicePermission = false;
836a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindPrintServicePermission = false;
83794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasBindNfcServicePermission = false;
8389d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasRequiredSafAttributes = false;
8399d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasBindNotificationListenerServicePermission = false;
840eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool hasBindDreamServicePermission = false;
841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // These two implement the implicit permissions that are granted
843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // to pre-1.6 applications.
844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteExternalStoragePermission = false;
845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadPhoneStatePermission = false;
846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If an app requests write storage, they will also get read storage.
848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadExternalStoragePermission = false;
849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Implement transition to read and write call log.
851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadContactsPermission = false;
852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteContactsPermission = false;
853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadCallLogPermission = false;
854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteCallLogPermission = false;
855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
856e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            // If an app declares itself as multiArch, we report the
857e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            // native libraries differently.
858e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            bool hasMultiArch = false;
859e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This next group of variables is used to implement a group of
861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // backward-compatibility heuristics necessitated by the addition of
862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // some new uses-feature constants in 2.1 and 2.2. In most cases, the
863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // heuristic is "if an app requests a permission but doesn't explicitly
864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // request the corresponding <uses-feature>, presume it's there anyway".
8652c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // 2.2 also added some other features that apps can request, but that
867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // have no corresponding permission, so we cannot implement any
868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // back-compatibility heuristic for them. The below are thus unnecessary
869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // (but are retained here for documentary purposes.)
870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specCompassFeature = false;
871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAccelerometerFeature = false;
872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specProximityFeature = false;
873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAmbientLightFeature = false;
874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specLiveWallpaperFeature = false;
875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int targetSdk = 0;
877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int smallScreen = 1;
878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int normalScreen = 1;
879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largeScreen = 1;
880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int xlargeScreen = 1;
881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int anyDensity = 1;
882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int requiresSmallestWidthDp = 0;
883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int compatibleWidthLimitDp = 0;
884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largestWidthLimitDp = 0;
885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 pkg;
886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityName;
887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityLabel;
888282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityIcon;
8890a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            String8 activityBanner;
890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 receiverName;
891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 serviceName;
892ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            Vector<String8> supportedInput;
8932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
8942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            FeatureGroup commonFeatures;
8952c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            Vector<FeatureGroup> featureGroups;
8962c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            KeyedVector<String8, ImpliedFeature> impliedFeatures;
8972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
898282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
899282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
901282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (depth < 2) {
902ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if (withinSupportsInput && !supportedInput.isEmpty()) {
903ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("supports-input: '");
904ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            const size_t N = supportedInput.size();
905ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            for (size_t i=0; i<N; i++) {
9062675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                printf("%s", ResTable::normalizeForOutput(
9072675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        supportedInput[i].string()).string());
908ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (i != N - 1) {
909ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("' '");
910ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else {
911ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("'\n");
912ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
913ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
914