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,
2519b8528fee4eed35b8e887ded0851d08eb2b10db6Chih-Hung Hsieh        uint32_t attrRes, const 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,
312cd154e95353e7af11314d2339500d6c7f85e181aDianne Hackborn    REQUIRED_FEATURE_ATTR = 0x1010557,
313cd154e95353e7af11314d2339500d6c7f85e181aDianne Hackborn    REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3162675f769673f69b0661ddee346292f25cb30a296Maurice ChuString8 getComponentName(String8 &pkgName, String8 &componentName) {
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = componentName.find(".");
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 retStr(pkgName);
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx == 0) {
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (idx < 0) {
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += ".";
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
3252675f769673f69b0661ddee346292f25cb30a296Maurice Chu        return componentName;
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3272675f769673f69b0661ddee346292f25cb30a296Maurice Chu    return retStr;
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3309cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinskistatic void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResXMLTree::event_code_t code;
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int depth = 0;
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool first = true;
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("compatible-screens:");
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code == ResXMLTree::END_TAG) {
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            depth--;
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (depth < 0) {
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code != ResXMLTree::START_TAG) {
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        depth++;
3489cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        const char16_t* ctag16 = tree.getElementName(&len);
3499cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        if (ctag16 == NULL) {
3509cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            *outError = "failed to get XML element name (bad string pool)";
3519cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            return;
3529cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        }
3539cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        String8 tag(ctag16);
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tag == "screen") {
355ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            int32_t screenSize = AaptXml::getIntegerAttribute(tree,
356ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    SCREEN_SIZE_ATTR);
357ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            int32_t screenDensity = AaptXml::getIntegerAttribute(tree,
358ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    SCREEN_DENSITY_ATTR);
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (screenSize > 0 && screenDensity > 0) {
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!first) {
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf(",");
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                first = false;
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("'%d/%d'", screenSize, screenDensity);
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("\n");
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
371cd154e95353e7af11314d2339500d6c7f85e181aDianne Hackbornstatic void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1,
372cd154e95353e7af11314d2339500d6c7f85e181aDianne Hackborn        const String8& requiredFeature = String8::empty(),
373cd154e95353e7af11314d2339500d6c7f85e181aDianne Hackborn        const String8& requiredNotFeature = String8::empty()) {
37458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
37558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (maxSdkVersion != -1) {
37658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski         printf(" maxSdkVersion='%d'", maxSdkVersion);
37758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
378cd154e95353e7af11314d2339500d6c7f85e181aDianne Hackborn    if (requiredFeature.length() > 0) {
379cd154e95353e7af11314d2339500d6c7f85e181aDianne Hackborn         printf(" requiredFeature='%s'", requiredFeature.string());
380cd154e95353e7af11314d2339500d6c7f85e181aDianne Hackborn    }
381cd154e95353e7af11314d2339500d6c7f85e181aDianne Hackborn    if (requiredNotFeature.length() > 0) {
382cd154e95353e7af11314d2339500d6c7f85e181aDianne Hackborn         printf(" requiredNotFeature='%s'", requiredNotFeature.string());
383cd154e95353e7af11314d2339500d6c7f85e181aDianne Hackborn    }
38458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("\n");
38558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
38658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (optional) {
38758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("optional-permission: name='%s'",
38858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                ResTable::normalizeForOutput(name.string()).string());
38958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        if (maxSdkVersion != -1) {
39058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            printf(" maxSdkVersion='%d'", maxSdkVersion);
39158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        }
39258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("\n");
39358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
39458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
39558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
3965f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinskistatic void printUsesPermissionSdk23(const String8& name, int maxSdkVersion=-1) {
3975f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    printf("uses-permission-sdk-23: ");
3985f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
3995f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    printf("name='%s'", ResTable::normalizeForOutput(name.string()).string());
4005f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    if (maxSdkVersion != -1) {
4015f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        printf(" maxSdkVersion='%d'", maxSdkVersion);
4025f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    }
4035f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    printf("\n");
4045f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski}
4055f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
4062386df23ac9e932a385b9c2fbddbf9e445eaada0Adam Lesinskistatic void printUsesImpliedPermission(const String8& name, const String8& reason,
4072386df23ac9e932a385b9c2fbddbf9e445eaada0Adam Lesinski        const int32_t maxSdkVersion = -1) {
4082386df23ac9e932a385b9c2fbddbf9e445eaada0Adam Lesinski    printf("uses-implied-permission: name='%s'",
4092386df23ac9e932a385b9c2fbddbf9e445eaada0Adam Lesinski            ResTable::normalizeForOutput(name.string()).string());
4102386df23ac9e932a385b9c2fbddbf9e445eaada0Adam Lesinski    if (maxSdkVersion != -1) {
4112386df23ac9e932a385b9c2fbddbf9e445eaada0Adam Lesinski        printf(" maxSdkVersion='%d'", maxSdkVersion);
4122386df23ac9e932a385b9c2fbddbf9e445eaada0Adam Lesinski    }
4132386df23ac9e932a385b9c2fbddbf9e445eaada0Adam Lesinski    printf(" reason='%s'\n", ResTable::normalizeForOutput(reason.string()).string());
41458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
41558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
4169b8528fee4eed35b8e887ded0851d08eb2b10db6Chih-Hung HsiehVector<String8> getNfcAidCategories(AssetManager& assets, const String8& xmlPath, bool offHost,
41794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        String8 *outError = NULL)
41894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski{
41994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
42094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    if (aidAsset == NULL) {
42194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (outError != NULL) *outError = "xml resource does not exist";
42294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        return Vector<String8>();
42394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
42494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
42594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
42694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
42794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    bool withinApduService = false;
42894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Vector<String8> categories;
42994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
43094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    String8 error;
43194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree tree;
43294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
43394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
43494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    size_t len;
43594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    int depth = 0;
43694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree::event_code_t code;
43794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
43894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (code == ResXMLTree::END_TAG) {
43994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth--;
4409cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
4419cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
4429cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
4439cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
4449cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
4459cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
44694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
44794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 0 && tag == serviceTagName) {
44894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                withinApduService = false;
44994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
45094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
45194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        } else if (code == ResXMLTree::START_TAG) {
45294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth++;
4539cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
4549cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
4559cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
4569cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
4579cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
4589cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
45994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
46094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 1) {
46194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == serviceTagName) {
46294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    withinApduService = true;
46394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
46494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            } else if (depth == 2 && withinApduService) {
46594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == "aid-group") {
466ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                    String8 category = AaptXml::getAttribute(tree, CATEGORY_ATTR, &error);
46794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (error != "") {
46894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (outError != NULL) *outError = error;
46994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        return Vector<String8>();
47094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
47194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
47294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    categories.add(category);
47394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
47494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
47594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        }
47694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
47794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    aidAsset->close();
47894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    return categories;
47994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski}
48094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
4819d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinskistatic void printComponentPresence(const char* componentName) {
4829d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    printf("provides-component:'%s'\n", componentName);
4839d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski}
4849d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
4852c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
4862c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a feature that has been automatically added due to
4872c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * a pre-requisite or some other reason.
4882c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
4892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct ImpliedFeature {
4905f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    ImpliedFeature() : impliedBySdk23(false) {}
4915f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    ImpliedFeature(const String8& n, bool sdk23) : name(n), impliedBySdk23(sdk23) {}
4925f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
4932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
4942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Name of the implied feature.
4952c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
4962c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name;
4972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
4982c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
4995f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski     * Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)?
5005f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski     */
5015f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    bool impliedBySdk23;
5025f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
5035f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    /**
5042c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * List of human-readable reasons for why this feature was implied.
5052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
5062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    SortedVector<String8> reasons;
5072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
5082c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
509694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinskistruct Feature {
510694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    Feature() : required(false), version(-1) {}
511d53e3bed1ca4a14b2a86d53eaef6969bd043176eChih-Hung Hsieh    explicit Feature(bool required, int32_t version = -1) : required(required), version(version) {}
512694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
513694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    /**
514694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski     * Whether the feature is required.
515694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski     */
516694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    bool required;
517694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
518694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    /**
519694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski     * What version of the feature is requested.
520694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski     */
521694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    int32_t version;
522694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski};
523694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
5242c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
5252c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a <feature-group> tag in the AndroidManifest.xml
5262c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
5272c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct FeatureGroup {
528d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    FeatureGroup() : openGLESVersion(-1) {}
529d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
5302c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
5312c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Human readable label
5322c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
5332c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 label;
5342c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5352c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
5362c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Explicit features defined in the group
5372c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
538694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski    KeyedVector<String8, Feature> features;
539d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
540d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    /**
541d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     * OpenGL ES version required
542d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     */
543d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    int openGLESVersion;
5442c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
5452c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
546ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinskistatic bool hasFeature(const char* name, const FeatureGroup& grp,
547ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski                       const KeyedVector<String8, ImpliedFeature>& implied) {
548ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    String8 name8(name);
549ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    ssize_t idx = grp.features.indexOfKey(name8);
550ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    if (idx < 0) {
551ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski        idx = implied.indexOfKey(name8);
552ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    }
553ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    return idx >= 0;
554ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski}
555ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski
5562c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
55743158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              const char* name, const String8& reason, bool sdk23) {
5582c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name8(name);
5592c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    ssize_t idx = impliedFeatures->indexOfKey(name8);
5602c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (idx < 0) {
5615f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        idx = impliedFeatures->add(name8, ImpliedFeature(name8, sdk23));
5622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
5635f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
5645f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    ImpliedFeature* feature = &impliedFeatures->editValueAt(idx);
5655f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
5665f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    // A non-sdk 23 implied feature takes precedence.
5675f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    if (feature->impliedBySdk23 && !sdk23) {
5685f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        feature->impliedBySdk23 = false;
5695f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    }
57043158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski    feature->reasons.add(reason);
5712c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
5722c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5735f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinskistatic void printFeatureGroupImpl(const FeatureGroup& grp,
5745f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                  const KeyedVector<String8, ImpliedFeature>* impliedFeatures) {
5752c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    printf("feature-group: label='%s'\n", grp.label.string());
5762c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
577d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    if (grp.openGLESVersion > 0) {
578d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        printf("  uses-gl-es: '0x%x'\n", grp.openGLESVersion);
579d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    }
580d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
5812c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numFeatures = grp.features.size();
5822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numFeatures; i++) {
583694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        const Feature& feature = grp.features[i];
584694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        const bool required = feature.required;
585694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        const int32_t version = feature.version;
5862c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5872c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const String8& featureName = grp.features.keyAt(i);
588694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        printf("  uses-feature%s: name='%s'", (required ? "" : "-not-required"),
5892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                ResTable::normalizeForOutput(featureName.string()).string());
590694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski
591694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        if (version > 0) {
592694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski            printf(" version='%d'", version);
593694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        }
594694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        printf("\n");
5952c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
5962c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
5972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numImpliedFeatures =
5982c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        (impliedFeatures != NULL) ? impliedFeatures->size() : 0;
5992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numImpliedFeatures; i++) {
6002c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i);
6012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        if (grp.features.indexOfKey(impliedFeature.name) >= 0) {
6022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // The feature is explicitly set, no need to use implied
6032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // definition.
6042c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            continue;
6052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        String8 printableFeatureName(ResTable::normalizeForOutput(
6082c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    impliedFeature.name.string()));
6095f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        const char* sdk23Suffix = impliedFeature.impliedBySdk23 ? "-sdk-23" : "";
6105f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
6115f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        printf("  uses-feature%s: name='%s'\n", sdk23Suffix, printableFeatureName.string());
6125f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        printf("  uses-implied-feature%s: name='%s' reason='", sdk23Suffix,
6135f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               printableFeatureName.string());
6142c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const size_t numReasons = impliedFeature.reasons.size();
6152c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        for (size_t j = 0; j < numReasons; j++) {
6162c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            printf("%s", impliedFeature.reasons[j].string());
6172c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            if (j + 2 < numReasons) {
6182c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", ");
6192c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            } else if (j + 1 < numReasons) {
6202c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", and ");
6212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            }
6222c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6232c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("'\n");
6242c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6252c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
6262c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6275f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinskistatic void printFeatureGroup(const FeatureGroup& grp) {
6285f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    printFeatureGroupImpl(grp, NULL);
6295f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski}
6305f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
6315f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinskistatic void printDefaultFeatureGroup(const FeatureGroup& grp,
6325f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                     const KeyedVector<String8, ImpliedFeature>& impliedFeatures) {
6335f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    printFeatureGroupImpl(grp, &impliedFeatures);
6345f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski}
6355f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
6362c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addParentFeatures(FeatureGroup* grp, const String8& name) {
6372c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (name == "android.hardware.camera.autofocus" ||
6382c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.camera.flash") {
639694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        grp->features.add(String8("android.hardware.camera"), Feature(true));
6402c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.location.gps" ||
6412c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.location.network") {
642694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        grp->features.add(String8("android.hardware.location"), Feature(true));
643ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    } else if (name == "android.hardware.faketouch.multitouch") {
644ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski        grp->features.add(String8("android.hardware.faketouch"), Feature(true));
645ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
646ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski            name == "android.hardware.faketouch.multitouch.jazzhands") {
647ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski        grp->features.add(String8("android.hardware.faketouch.multitouch"), Feature(true));
648ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski        grp->features.add(String8("android.hardware.faketouch"), Feature(true));
6492c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch") {
650694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
651ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
652ca955a4c3ab3d4b83c6e9d5278bcd8d2258d44adAdam Lesinski            name == "android.hardware.touchscreen.multitouch.jazzhands") {
653694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen.multitouch"), Feature(true));
654694d0a7dfd281060c9f8d92a79bda1b7071affe3Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
655d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    } else if (name == "android.hardware.opengles.aep") {
656d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        const int openGLESVersion31 = 0x00030001;
657d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        if (openGLESVersion31 > grp->openGLESVersion) {
658d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski            grp->openGLESVersion = openGLESVersion31;
659d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        }
6602c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6612c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
6622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6635f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinskistatic void addImpliedFeaturesForPermission(const int targetSdk, const String8& name,
6645f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                            KeyedVector<String8, ImpliedFeature>* impliedFeatures,
6655f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski                                            bool impliedBySdk23Permission) {
6665f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    if (name == "android.permission.CAMERA") {
6675f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.camera",
66843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8::format("requested %s permission", name.string()),
66943158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
6705f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
67143158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski        if (targetSdk < SDK_LOLLIPOP) {
67243158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
67343158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("requested %s permission", name.string()),
67443158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
67543158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
67643158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
67743158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
67843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski        }
6795f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.location",
68043158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                String8::format("requested %s permission", name.string()),
68143158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                impliedBySdk23Permission);
6825f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
68343158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski        if (targetSdk < SDK_LOLLIPOP) {
68443158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.location.network",
68543158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("requested %s permission", name.string()),
68643158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
68743158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.location.network",
68843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
68943158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
69043158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski        }
6915f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.location",
69243158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8::format("requested %s permission", name.string()),
69343158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
69443158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski    } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
69543158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski               name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
6965f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.INSTALL_LOCATION_PROVIDER") {
6975f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.location",
69843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8::format("requested %s permission", name.string()),
69943158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
7005f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.BLUETOOTH" ||
7015f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.BLUETOOTH_ADMIN") {
70243158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski        if (targetSdk > SDK_DONUT) {
7035f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
70443158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("requested %s permission", name.string()),
70543158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
7065f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski            addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
70743158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              String8::format("targetSdkVersion > %d", SDK_DONUT),
70843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                              impliedBySdk23Permission);
7095f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        }
7105f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.RECORD_AUDIO") {
7115f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.microphone",
71243158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8::format("requested %s permission", name.string()),
71343158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
7145f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
7155f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.CHANGE_WIFI_STATE" ||
7165f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
7175f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.wifi",
71843158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8::format("requested %s permission", name.string()),
71943158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
7205f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    } else if (name == "android.permission.CALL_PHONE" ||
7215f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.CALL_PRIVILEGED" ||
7225f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.MODIFY_PHONE_STATE" ||
7235f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.PROCESS_OUTGOING_CALLS" ||
7245f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.READ_SMS" ||
7255f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.RECEIVE_SMS" ||
7265f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.RECEIVE_MMS" ||
7275f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.RECEIVE_WAP_PUSH" ||
7285f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.SEND_SMS" ||
7295f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.WRITE_APN_SETTINGS" ||
7305f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski               name == "android.permission.WRITE_SMS") {
7315f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski        addImpliedFeature(impliedFeatures, "android.hardware.telephony",
73243158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          String8("requested a telephony permission"),
73343158773b469c2d5b23e52998d0afba9a4b34323Adam Lesinski                          impliedBySdk23Permission);
7345f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski    }
7355f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski}
7365f3b2ecb3e9d27e77bd59c7b9006a6239b773944Adam Lesinski
737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "dump" command, to extract select data from an archive.
739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiextern char CONSOLE_DATA[2925]; // see EOF
741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doDump(Bundle* bundle)
742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump option specified\n");
747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump file specified\n");
752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* option = bundle->getFileSpecEntry(0);
756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* filename = bundle->getFileSpecEntry(1);
757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    AssetManager assets;
759f85e41f29a0e9313c2d4725f9d9648591ea49f3bNarayan Kamath    int32_t assetsCookie;
760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
763282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
764282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
76557fe48389f845709db23234088b97f4e30307ff4Adam Lesinski    // Now add any dependencies passed in.
76657fe48389f845709db23234088b97f4e30307ff4Adam Lesinski    for (size_t i = 0; i < bundle->getPackageIncludes().size(); i++) {
76757fe48389f845709db23234088b97f4e30307ff4Adam Lesinski      const String8& assetPath = bundle->getPackageIncludes()[i];
76857fe48389f845709db23234088b97f4e30307ff4Adam Lesinski      if (!assets.addAssetPath(assetPath, NULL)) {
76957fe48389f845709db23234088b97f4e30307ff4Adam Lesinski        fprintf(stderr, "ERROR: included asset path %s could not be loaded\n", assetPath.string());
77057fe48389f845709db23234088b97f4e30307ff4Adam Lesinski        return 1;
77157fe48389f845709db23234088b97f4e30307ff4Adam Lesinski      }
77257fe48389f845709db23234088b97f4e30307ff4Adam Lesinski    }
77357fe48389f845709db23234088b97f4e30307ff4Adam Lesinski
774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make a dummy config for retrieving resources...  we need to supply
775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // non-default values for some configs so that we can retrieve resources
776282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // in the app that don't have a default.  The most important of these is
777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the API version because key resources like icons will have an implicit
778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // version if they are using newer config types like density.
779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_config config;
78091447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath    memset(&config, 0, sizeof(ResTable_config));
781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[0] = 'e';
782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[1] = 'n';
783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[0] = 'U';
784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[1] = 'S';
785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.orientation = ResTable_config::ORIENTATION_PORT;
786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.density = ResTable_config::DENSITY_MEDIUM;
787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.sdkVersion = 10000; // Very high.
788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenWidthDp = 320;
789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenHeightDp = 480;
790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.smallestScreenWidthDp = 320;
791c2dea8daea2ae0001d56689d96ce1066012b7b40Adam Lesinski    config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL;
792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets.setConfiguration(config);
793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ResTable& res = assets.getResources(false);
7956800165351b693fa7e4bcf0f205655f0cd16b361Dan Albert    if (res.getError() != NO_ERROR) {
79625e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
79763e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        return 1;
798