blob: cadac02f1e04967850c5335d81e02803b1e77356 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001//
2// Copyright 2006 The Android Open Source Project
3//
4// Android Asset Packaging Tool main entry point.
5//
6#include "Main.h"
7#include "Bundle.h"
Dianne Hackborne6b68032011-10-13 16:26:02 -07008#include "ResourceFilter.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009#include "ResourceTable.h"
Xavier Ducrohetb1f6ad82012-12-21 09:54:02 -080010#include "Images.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011#include "XMLNode.h"
12
Mathias Agopian3b4062e2009-05-31 19:13:00 -070013#include <utils/Log.h>
14#include <utils/threads.h>
15#include <utils/List.h>
16#include <utils/Errors.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080017
18#include <fcntl.h>
19#include <errno.h>
20
21using namespace android;
22
23/*
24 * Show version info. All the cool kids do it.
25 */
26int doVersion(Bundle* bundle)
27{
28 if (bundle->getFileSpecCount() != 0)
29 printf("(ignoring extra arguments)\n");
30 printf("Android Asset Packaging Tool, v0.2\n");
31
32 return 0;
33}
34
35
36/*
37 * Open the file read only. The call fails if the file doesn't exist.
38 *
39 * Returns NULL on failure.
40 */
41ZipFile* openReadOnly(const char* fileName)
42{
43 ZipFile* zip;
44 status_t result;
45
46 zip = new ZipFile;
47 result = zip->open(fileName, ZipFile::kOpenReadOnly);
48 if (result != NO_ERROR) {
49 if (result == NAME_NOT_FOUND)
50 fprintf(stderr, "ERROR: '%s' not found\n", fileName);
51 else if (result == PERMISSION_DENIED)
52 fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
53 else
54 fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
55 fileName);
56 delete zip;
57 return NULL;
58 }
59
60 return zip;
61}
62
63/*
64 * Open the file read-write. The file will be created if it doesn't
65 * already exist and "okayToCreate" is set.
66 *
67 * Returns NULL on failure.
68 */
69ZipFile* openReadWrite(const char* fileName, bool okayToCreate)
70{
71 ZipFile* zip = NULL;
72 status_t result;
73 int flags;
74
75 flags = ZipFile::kOpenReadWrite;
76 if (okayToCreate)
77 flags |= ZipFile::kOpenCreate;
78
79 zip = new ZipFile;
80 result = zip->open(fileName, flags);
81 if (result != NO_ERROR) {
82 delete zip;
83 zip = NULL;
84 goto bail;
85 }
86
87bail:
88 return zip;
89}
90
91
92/*
93 * Return a short string describing the compression method.
94 */
95const char* compressionName(int method)
96{
97 if (method == ZipEntry::kCompressStored)
98 return "Stored";
99 else if (method == ZipEntry::kCompressDeflated)
100 return "Deflated";
101 else
102 return "Unknown";
103}
104
105/*
106 * Return the percent reduction in size (0% == no compression).
107 */
108int calcPercent(long uncompressedLen, long compressedLen)
109{
110 if (!uncompressedLen)
111 return 0;
112 else
113 return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
114}
115
116/*
117 * Handle the "list" command, which can be a simple file dump or
118 * a verbose listing.
119 *
120 * The verbose listing closely matches the output of the Info-ZIP "unzip"
121 * command.
122 */
123int doList(Bundle* bundle)
124{
125 int result = 1;
126 ZipFile* zip = NULL;
127 const ZipEntry* entry;
128 long totalUncLen, totalCompLen;
129 const char* zipFileName;
130
131 if (bundle->getFileSpecCount() != 1) {
132 fprintf(stderr, "ERROR: specify zip file name (only)\n");
133 goto bail;
134 }
135 zipFileName = bundle->getFileSpecEntry(0);
136
137 zip = openReadOnly(zipFileName);
138 if (zip == NULL)
139 goto bail;
140
141 int count, i;
142
143 if (bundle->getVerbose()) {
144 printf("Archive: %s\n", zipFileName);
145 printf(
Kenny Rootfb2a9462010-08-25 07:36:31 -0700146 " Length Method Size Ratio Offset Date Time CRC-32 Name\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 printf(
Kenny Rootfb2a9462010-08-25 07:36:31 -0700148 "-------- ------ ------- ----- ------- ---- ---- ------ ----\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 }
150
151 totalUncLen = totalCompLen = 0;
152
153 count = zip->getNumEntries();
154 for (i = 0; i < count; i++) {
155 entry = zip->getEntryByIndex(i);
156 if (bundle->getVerbose()) {
157 char dateBuf[32];
158 time_t when;
159
160 when = entry->getModWhen();
161 strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
162 localtime(&when));
163
Kenny Rootfb2a9462010-08-25 07:36:31 -0700164 printf("%8ld %-7.7s %7ld %3d%% %8zd %s %08lx %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 (long) entry->getUncompressedLen(),
166 compressionName(entry->getCompressionMethod()),
167 (long) entry->getCompressedLen(),
168 calcPercent(entry->getUncompressedLen(),
169 entry->getCompressedLen()),
Kenny Rootfb2a9462010-08-25 07:36:31 -0700170 (size_t) entry->getLFHOffset(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 dateBuf,
172 entry->getCRC32(),
173 entry->getFileName());
174 } else {
175 printf("%s\n", entry->getFileName());
176 }
177
178 totalUncLen += entry->getUncompressedLen();
179 totalCompLen += entry->getCompressedLen();
180 }
181
182 if (bundle->getVerbose()) {
183 printf(
184 "-------- ------- --- -------\n");
185 printf("%8ld %7ld %2d%% %d files\n",
186 totalUncLen,
187 totalCompLen,
188 calcPercent(totalUncLen, totalCompLen),
189 zip->getNumEntries());
190 }
191
192 if (bundle->getAndroidList()) {
193 AssetManager assets;
194 if (!assets.addAssetPath(String8(zipFileName), NULL)) {
195 fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
196 goto bail;
197 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 const ResTable& res = assets.getResources(false);
200 if (&res == NULL) {
201 printf("\nNo resource table found.\n");
202 } else {
Steve Blockf1ff21a2010-06-14 17:34:04 +0100203#ifndef HAVE_ANDROID_OS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 printf("\nResource table:\n");
Dianne Hackborne17086b2009-06-19 15:13:28 -0700205 res.print(false);
Steve Blockf1ff21a2010-06-14 17:34:04 +0100206#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
210 Asset::ACCESS_BUFFER);
211 if (manifestAsset == NULL) {
212 printf("\nNo AndroidManifest.xml found.\n");
213 } else {
214 printf("\nAndroid manifest:\n");
215 ResXMLTree tree;
216 tree.setTo(manifestAsset->getBuffer(true),
217 manifestAsset->getLength());
218 printXMLBlock(&tree);
219 }
220 delete manifestAsset;
221 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 result = 0;
224
225bail:
226 delete zip;
227 return result;
228}
229
230static ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes)
231{
232 size_t N = tree.getAttributeCount();
233 for (size_t i=0; i<N; i++) {
234 if (tree.getAttributeNameResID(i) == attrRes) {
235 return (ssize_t)i;
236 }
237 }
238 return -1;
239}
240
Joe Onorato1553c822009-08-30 13:36:22 -0700241String8 getAttribute(const ResXMLTree& tree, const char* ns,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 const char* attr, String8* outError)
243{
244 ssize_t idx = tree.indexOfAttribute(ns, attr);
245 if (idx < 0) {
246 return String8();
247 }
248 Res_value value;
249 if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
250 if (value.dataType != Res_value::TYPE_STRING) {
251 if (outError != NULL) *outError = "attribute is not a string value";
252 return String8();
253 }
254 }
255 size_t len;
256 const uint16_t* str = tree.getAttributeStringValue(idx, &len);
257 return str ? String8(str, len) : String8();
258}
259
260static String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError)
261{
262 ssize_t idx = indexOfAttribute(tree, attrRes);
263 if (idx < 0) {
264 return String8();
265 }
266 Res_value value;
267 if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
268 if (value.dataType != Res_value::TYPE_STRING) {
269 if (outError != NULL) *outError = "attribute is not a string value";
270 return String8();
271 }
272 }
273 size_t len;
274 const uint16_t* str = tree.getAttributeStringValue(idx, &len);
275 return str ? String8(str, len) : String8();
276}
277
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700278static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes,
279 String8* outError, int32_t defValue = -1)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280{
281 ssize_t idx = indexOfAttribute(tree, attrRes);
282 if (idx < 0) {
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700283 return defValue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 }
285 Res_value value;
286 if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700287 if (value.dataType < Res_value::TYPE_FIRST_INT
288 || value.dataType > Res_value::TYPE_LAST_INT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 if (outError != NULL) *outError = "attribute is not an integer value";
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700290 return defValue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 }
292 }
293 return value.data;
294}
295
Dianne Hackbornf77ae6e2011-06-16 11:11:23 -0700296static int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree,
297 uint32_t attrRes, String8* outError, int32_t defValue = -1)
298{
299 ssize_t idx = indexOfAttribute(tree, attrRes);
300 if (idx < 0) {
301 return defValue;
302 }
303 Res_value value;
304 if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
305 if (value.dataType == Res_value::TYPE_REFERENCE) {
306 resTable->resolveReference(&value, 0);
307 }
308 if (value.dataType < Res_value::TYPE_FIRST_INT
309 || value.dataType > Res_value::TYPE_LAST_INT) {
310 if (outError != NULL) *outError = "attribute is not an integer value";
311 return defValue;
312 }
313 }
314 return value.data;
315}
316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317static String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree,
318 uint32_t attrRes, String8* outError)
319{
320 ssize_t idx = indexOfAttribute(tree, attrRes);
321 if (idx < 0) {
322 return String8();
323 }
324 Res_value value;
325 if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
326 if (value.dataType == Res_value::TYPE_STRING) {
327 size_t len;
328 const uint16_t* str = tree.getAttributeStringValue(idx, &len);
329 return str ? String8(str, len) : String8();
330 }
331 resTable->resolveReference(&value, 0);
332 if (value.dataType != Res_value::TYPE_STRING) {
333 if (outError != NULL) *outError = "attribute is not a string value";
334 return String8();
335 }
336 }
337 size_t len;
338 const Res_value* value2 = &value;
339 const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len);
340 return str ? String8(str, len) : String8();
341}
342
343// These are attribute resource constants for the platform, as found
344// in android.R.attr
345enum {
Dianne Hackbornf77ae6e2011-06-16 11:11:23 -0700346 LABEL_ATTR = 0x01010001,
347 ICON_ATTR = 0x01010002,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 NAME_ATTR = 0x01010003,
Dan Morrillb6ec11e2012-04-03 12:44:40 -0700349 DEBUGGABLE_ATTR = 0x0101000f,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 VERSION_CODE_ATTR = 0x0101021b,
351 VERSION_NAME_ATTR = 0x0101021c,
Dianne Hackbornf77ae6e2011-06-16 11:11:23 -0700352 SCREEN_ORIENTATION_ATTR = 0x0101001e,
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700353 MIN_SDK_VERSION_ATTR = 0x0101020c,
Suchi Amalapurapu75c49842009-08-14 15:13:09 -0700354 MAX_SDK_VERSION_ATTR = 0x01010271,
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700355 REQ_TOUCH_SCREEN_ATTR = 0x01010227,
356 REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
357 REQ_HARD_KEYBOARD_ATTR = 0x01010229,
358 REQ_NAVIGATION_ATTR = 0x0101022a,
359 REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
360 TARGET_SDK_VERSION_ATTR = 0x01010270,
361 TEST_ONLY_ATTR = 0x01010272,
Dianne Hackborna0b46c92010-10-21 15:32:06 -0700362 ANY_DENSITY_ATTR = 0x0101026c,
Dianne Hackborne5276a72009-08-27 16:28:44 -0700363 GL_ES_VERSION_ATTR = 0x01010281,
Dianne Hackborn723738c2009-06-25 19:48:04 -0700364 SMALL_SCREEN_ATTR = 0x01010284,
365 NORMAL_SCREEN_ATTR = 0x01010285,
366 LARGE_SCREEN_ATTR = 0x01010286,
Dianne Hackbornf43489d2010-08-20 12:44:33 -0700367 XLARGE_SCREEN_ATTR = 0x010102bf,
Dianne Hackborne5276a72009-08-27 16:28:44 -0700368 REQUIRED_ATTR = 0x0101028e,
Dianne Hackborna0b46c92010-10-21 15:32:06 -0700369 SCREEN_SIZE_ATTR = 0x010102ca,
370 SCREEN_DENSITY_ATTR = 0x010102cb,
Dianne Hackborne289bff2011-06-13 19:33:22 -0700371 REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
372 COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
373 LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
Kenny Root56088a52011-09-29 13:49:45 -0700374 PUBLIC_KEY_ATTR = 0x010103a6,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375};
376
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700377const char *getComponentName(String8 &pkgName, String8 &componentName) {
378 ssize_t idx = componentName.find(".");
379 String8 retStr(pkgName);
380 if (idx == 0) {
381 retStr += componentName;
382 } else if (idx < 0) {
383 retStr += ".";
384 retStr += componentName;
385 } else {
386 return componentName.string();
387 }
388 return retStr.string();
389}
390
Dianne Hackborna0b46c92010-10-21 15:32:06 -0700391static void printCompatibleScreens(ResXMLTree& tree) {
392 size_t len;
393 ResXMLTree::event_code_t code;
394 int depth = 0;
395 bool first = true;
396 printf("compatible-screens:");
397 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
398 if (code == ResXMLTree::END_TAG) {
399 depth--;
400 if (depth < 0) {
401 break;
402 }
403 continue;
404 }
405 if (code != ResXMLTree::START_TAG) {
406 continue;
407 }
408 depth++;
409 String8 tag(tree.getElementName(&len));
410 if (tag == "screen") {
411 int32_t screenSize = getIntegerAttribute(tree,
412 SCREEN_SIZE_ATTR, NULL, -1);
413 int32_t screenDensity = getIntegerAttribute(tree,
414 SCREEN_DENSITY_ATTR, NULL, -1);
415 if (screenSize > 0 && screenDensity > 0) {
416 if (!first) {
417 printf(",");
418 }
419 first = false;
420 printf("'%d/%d'", screenSize, screenDensity);
421 }
422 }
423 }
424 printf("\n");
425}
426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427/*
428 * Handle the "dump" command, to extract select data from an archive.
429 */
Dan Morrille74763e2012-01-06 10:47:10 -0800430extern char CONSOLE_DATA[2925]; // see EOF
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431int doDump(Bundle* bundle)
432{
433 status_t result = UNKNOWN_ERROR;
434 Asset* asset = NULL;
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 if (bundle->getFileSpecCount() < 1) {
437 fprintf(stderr, "ERROR: no dump option specified\n");
438 return 1;
439 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 if (bundle->getFileSpecCount() < 2) {
442 fprintf(stderr, "ERROR: no dump file specified\n");
443 return 1;
444 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 const char* option = bundle->getFileSpecEntry(0);
447 const char* filename = bundle->getFileSpecEntry(1);
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 AssetManager assets;
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700450 void* assetsCookie;
451 if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
453 return 1;
454 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700455
Dianne Hackborne289bff2011-06-13 19:33:22 -0700456 // Make a dummy config for retrieving resources... we need to supply
457 // non-default values for some configs so that we can retrieve resources
458 // in the app that don't have a default. The most important of these is
459 // the API version because key resources like icons will have an implicit
460 // version if they are using newer config types like density.
461 ResTable_config config;
462 config.language[0] = 'e';
463 config.language[1] = 'n';
464 config.country[0] = 'U';
465 config.country[1] = 'S';
466 config.orientation = ResTable_config::ORIENTATION_PORT;
467 config.density = ResTable_config::DENSITY_MEDIUM;
468 config.sdkVersion = 10000; // Very high.
469 config.screenWidthDp = 320;
470 config.screenHeightDp = 480;
471 config.smallestScreenWidthDp = 320;
472 assets.setConfiguration(config);
473
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 const ResTable& res = assets.getResources(false);
475 if (&res == NULL) {
476 fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
477 goto bail;
478 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 if (strcmp("resources", option) == 0) {
Steve Blockf1ff21a2010-06-14 17:34:04 +0100481#ifndef HAVE_ANDROID_OS
Dianne Hackborne17086b2009-06-19 15:13:28 -0700482 res.print(bundle->getValues());
Steve Blockf1ff21a2010-06-14 17:34:04 +0100483#endif
Dianne Hackborn6c997a92012-01-31 11:27:43 -0800484
485 } else if (strcmp("strings", option) == 0) {
486 const ResStringPool* pool = res.getTableStringBlock(0);
487 printStringPool(pool);
488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 } else if (strcmp("xmltree", option) == 0) {
490 if (bundle->getFileSpecCount() < 3) {
491 fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
492 goto bail;
493 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 for (int i=2; i<bundle->getFileSpecCount(); i++) {
496 const char* resname = bundle->getFileSpecEntry(i);
497 ResXMLTree tree;
498 asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER);
499 if (asset == NULL) {
Kenny Root44b283d2009-09-01 19:03:11 -0500500 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 goto bail;
502 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 if (tree.setTo(asset->getBuffer(true),
505 asset->getLength()) != NO_ERROR) {
506 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
507 goto bail;
508 }
509 tree.restart();
510 printXMLBlock(&tree);
Kenny Root19138462009-12-04 09:38:48 -0800511 tree.uninit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 delete asset;
513 asset = NULL;
514 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 } else if (strcmp("xmlstrings", option) == 0) {
517 if (bundle->getFileSpecCount() < 3) {
518 fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
519 goto bail;
520 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 for (int i=2; i<bundle->getFileSpecCount(); i++) {
523 const char* resname = bundle->getFileSpecEntry(i);
524 ResXMLTree tree;
525 asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER);
526 if (asset == NULL) {
Kenny Root44b283d2009-09-01 19:03:11 -0500527 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 goto bail;
529 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 if (tree.setTo(asset->getBuffer(true),
532 asset->getLength()) != NO_ERROR) {
533 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
534 goto bail;
535 }
536 printStringPool(&tree.getStrings());
537 delete asset;
538 asset = NULL;
539 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 } else {
542 ResXMLTree tree;
543 asset = assets.openNonAsset("AndroidManifest.xml",
544 Asset::ACCESS_BUFFER);
545 if (asset == NULL) {
546 fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
547 goto bail;
548 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700549
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 if (tree.setTo(asset->getBuffer(true),
551 asset->getLength()) != NO_ERROR) {
552 fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
553 goto bail;
554 }
555 tree.restart();
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 if (strcmp("permissions", option) == 0) {
558 size_t len;
559 ResXMLTree::event_code_t code;
560 int depth = 0;
561 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
562 if (code == ResXMLTree::END_TAG) {
563 depth--;
564 continue;
565 }
566 if (code != ResXMLTree::START_TAG) {
567 continue;
568 }
569 depth++;
570 String8 tag(tree.getElementName(&len));
571 //printf("Depth %d tag %s\n", depth, tag.string());
572 if (depth == 1) {
573 if (tag != "manifest") {
574 fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
575 goto bail;
576 }
577 String8 pkg = getAttribute(tree, NULL, "package", NULL);
578 printf("package: %s\n", pkg.string());
579 } else if (depth == 2 && tag == "permission") {
580 String8 error;
581 String8 name = getAttribute(tree, NAME_ATTR, &error);
582 if (error != "") {
583 fprintf(stderr, "ERROR: %s\n", error.string());
584 goto bail;
585 }
586 printf("permission: %s\n", name.string());
587 } else if (depth == 2 && tag == "uses-permission") {
588 String8 error;
589 String8 name = getAttribute(tree, NAME_ATTR, &error);
590 if (error != "") {
591 fprintf(stderr, "ERROR: %s\n", error.string());
592 goto bail;
593 }
594 printf("uses-permission: %s\n", name.string());
Nick Kralevich1bcc3d62013-04-03 09:00:02 -0700595 int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
596 if (!req) {
597 printf("optional-permission: %s\n", name.string());
598 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 }
600 }
601 } else if (strcmp("badging", option) == 0) {
Dianne Hackborne289bff2011-06-13 19:33:22 -0700602 Vector<String8> locales;
603 res.getLocales(&locales);
604
605 Vector<ResTable_config> configs;
606 res.getConfigurations(&configs);
607 SortedVector<int> densities;
608 const size_t NC = configs.size();
609 for (size_t i=0; i<NC; i++) {
610 int dens = configs[i].density;
611 if (dens == 0) dens = 160;
612 densities.add(dens);
613 }
614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 size_t len;
616 ResXMLTree::event_code_t code;
617 int depth = 0;
618 String8 error;
619 bool withinActivity = false;
620 bool isMainActivity = false;
621 bool isLauncherActivity = false;
Suchi Amalapurapu1b125982009-08-18 01:42:27 -0700622 bool isSearchable = false;
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700623 bool withinApplication = false;
624 bool withinReceiver = false;
Suchi Amalapurapu1b125982009-08-18 01:42:27 -0700625 bool withinService = false;
626 bool withinIntentFilter = false;
627 bool hasMainActivity = false;
628 bool hasOtherActivities = false;
629 bool hasOtherReceivers = false;
630 bool hasOtherServices = false;
631 bool hasWallpaperService = false;
632 bool hasImeService = false;
633 bool hasWidgetReceivers = false;
634 bool hasIntentFilter = false;
635 bool actMainActivity = false;
636 bool actWidgetReceivers = false;
637 bool actImeService = false;
638 bool actWallpaperService = false;
Dan Morrill89d97c12010-05-03 16:13:14 -0700639
Kenny Root063a44e2011-12-08 08:46:03 -0800640 // These two implement the implicit permissions that are granted
641 // to pre-1.6 applications.
642 bool hasWriteExternalStoragePermission = false;
643 bool hasReadPhoneStatePermission = false;
644
Dianne Hackborn79245122012-03-12 10:51:26 -0700645 // If an app requests write storage, they will also get read storage.
646 bool hasReadExternalStoragePermission = false;
647
Dianne Hackborn31b0e0e2012-04-05 19:33:30 -0700648 // Implement transition to read and write call log.
649 bool hasReadContactsPermission = false;
650 bool hasWriteContactsPermission = false;
651 bool hasReadCallLogPermission = false;
652 bool hasWriteCallLogPermission = false;
653
Dan Morrill89d97c12010-05-03 16:13:14 -0700654 // This next group of variables is used to implement a group of
655 // backward-compatibility heuristics necessitated by the addition of
656 // some new uses-feature constants in 2.1 and 2.2. In most cases, the
657 // heuristic is "if an app requests a permission but doesn't explicitly
658 // request the corresponding <uses-feature>, presume it's there anyway".
659 bool specCameraFeature = false; // camera-related
660 bool specCameraAutofocusFeature = false;
661 bool reqCameraAutofocusFeature = false;
662 bool reqCameraFlashFeature = false;
Dianne Hackborne5276a72009-08-27 16:28:44 -0700663 bool hasCameraPermission = false;
Dan Morrill89d97c12010-05-03 16:13:14 -0700664 bool specLocationFeature = false; // location-related
665 bool specNetworkLocFeature = false;
666 bool reqNetworkLocFeature = false;
Dianne Hackbornef05e072010-03-01 17:43:39 -0800667 bool specGpsFeature = false;
Dan Morrill89d97c12010-05-03 16:13:14 -0700668 bool reqGpsFeature = false;
669 bool hasMockLocPermission = false;
670 bool hasCoarseLocPermission = false;
Dianne Hackbornef05e072010-03-01 17:43:39 -0800671 bool hasGpsPermission = false;
Dan Morrill89d97c12010-05-03 16:13:14 -0700672 bool hasGeneralLocPermission = false;
673 bool specBluetoothFeature = false; // Bluetooth API-related
674 bool hasBluetoothPermission = false;
675 bool specMicrophoneFeature = false; // microphone-related
676 bool hasRecordAudioPermission = false;
677 bool specWiFiFeature = false;
678 bool hasWiFiPermission = false;
679 bool specTelephonyFeature = false; // telephony-related
680 bool reqTelephonySubFeature = false;
681 bool hasTelephonyPermission = false;
682 bool specTouchscreenFeature = false; // touchscreen-related
683 bool specMultitouchFeature = false;
684 bool reqDistinctMultitouchFeature = false;
Dianne Hackborne289bff2011-06-13 19:33:22 -0700685 bool specScreenPortraitFeature = false;
686 bool specScreenLandscapeFeature = false;
Dianne Hackbornf77ae6e2011-06-16 11:11:23 -0700687 bool reqScreenPortraitFeature = false;
688 bool reqScreenLandscapeFeature = false;
Dan Morrill89d97c12010-05-03 16:13:14 -0700689 // 2.2 also added some other features that apps can request, but that
690 // have no corresponding permission, so we cannot implement any
691 // back-compatibility heuristic for them. The below are thus unnecessary
692 // (but are retained here for documentary purposes.)
693 //bool specCompassFeature = false;
694 //bool specAccelerometerFeature = false;
695 //bool specProximityFeature = false;
696 //bool specAmbientLightFeature = false;
697 //bool specLiveWallpaperFeature = false;
698
Dianne Hackborn723738c2009-06-25 19:48:04 -0700699 int targetSdk = 0;
700 int smallScreen = 1;
701 int normalScreen = 1;
702 int largeScreen = 1;
Dianne Hackbornf43489d2010-08-20 12:44:33 -0700703 int xlargeScreen = 1;
Dianne Hackborna0b46c92010-10-21 15:32:06 -0700704 int anyDensity = 1;
Dianne Hackborne289bff2011-06-13 19:33:22 -0700705 int requiresSmallestWidthDp = 0;
706 int compatibleWidthLimitDp = 0;
707 int largestWidthLimitDp = 0;
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700708 String8 pkg;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 String8 activityName;
710 String8 activityLabel;
711 String8 activityIcon;
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700712 String8 receiverName;
Suchi Amalapurapu1b125982009-08-18 01:42:27 -0700713 String8 serviceName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
715 if (code == ResXMLTree::END_TAG) {
716 depth--;
Suchi Amalapurapu1b125982009-08-18 01:42:27 -0700717 if (depth < 2) {
718 withinApplication = false;
719 } else if (depth < 3) {
720 if (withinActivity && isMainActivity && isLauncherActivity) {
721 const char *aName = getComponentName(pkg, activityName);
Dianne Hackborne289bff2011-06-13 19:33:22 -0700722 printf("launchable-activity:");
Suchi Amalapurapu1b125982009-08-18 01:42:27 -0700723 if (aName != NULL) {
Dianne Hackborne289bff2011-06-13 19:33:22 -0700724 printf(" name='%s' ", aName);
Suchi Amalapurapu1b125982009-08-18 01:42:27 -0700725 }
Dianne Hackborne289bff2011-06-13 19:33:22 -0700726 printf(" label='%s' icon='%s'\n",
Suchi Amalapurapu1b125982009-08-18 01:42:27 -0700727 activityLabel.string(),
728 activityIcon.string());
729 }
730 if (!hasIntentFilter) {
731 hasOtherActivities |= withinActivity;
732 hasOtherReceivers |= withinReceiver;
733 hasOtherServices |= withinService;
734 }
735 withinActivity = false;
736 withinService = false;
737 withinReceiver = false;
738 hasIntentFilter = false;
739 isMainActivity = isLauncherActivity = false;
740 } else if (depth < 4) {
741 if (withinIntentFilter) {
742 if (withinActivity) {
743 hasMainActivity |= actMainActivity;
744 hasOtherActivities |= !actMainActivity;
745 } else if (withinReceiver) {
746 hasWidgetReceivers |= actWidgetReceivers;
747 hasOtherReceivers |= !actWidgetReceivers;
748 } else if (withinService) {
749 hasImeService |= actImeService;
750 hasWallpaperService |= actWallpaperService;
751 hasOtherServices |= (!actImeService && !actWallpaperService);
752 }
753 }
754 withinIntentFilter = false;
755 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 continue;
757 }
758 if (code != ResXMLTree::START_TAG) {
759 continue;
760 }
761 depth++;
762 String8 tag(tree.getElementName(&len));
Suchi Amalapurapu1b125982009-08-18 01:42:27 -0700763 //printf("Depth %d, %s\n", depth, tag.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 if (depth == 1) {
765 if (tag != "manifest") {
766 fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
767 goto bail;
768 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700769 pkg = getAttribute(tree, NULL, "package", NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 printf("package: name='%s' ", pkg.string());
771 int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error);
772 if (error != "") {
773 fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string());
774 goto bail;
775 }
776 if (versionCode > 0) {
777 printf("versionCode='%d' ", versionCode);
778 } else {
779 printf("versionCode='' ");
780 }
Dianne Hackborncf244ad2010-03-09 15:00:30 -0800781 String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 if (error != "") {
783 fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string());
784 goto bail;
785 }
786 printf("versionName='%s'\n", versionName.string());
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700787 } else if (depth == 2) {
788 withinApplication = false;
789 if (tag == "application") {
790 withinApplication = true;
Dianne Hackborne289bff2011-06-13 19:33:22 -0700791
792 String8 label;
793 const size_t NL = locales.size();
794 for (size_t i=0; i<NL; i++) {
795 const char* localeStr = locales[i].string();
796 assets.setLocale(localeStr != NULL ? localeStr : "");
797 String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
798 if (llabel != "") {
799 if (localeStr == NULL || strlen(localeStr) == 0) {
800 label = llabel;
801 printf("application-label:'%s'\n", llabel.string());
802 } else {
803 if (label == "") {
804 label = llabel;
805 }
806 printf("application-label-%s:'%s'\n", localeStr,
807 llabel.string());
808 }
809 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700810 }
Dianne Hackborne289bff2011-06-13 19:33:22 -0700811
812 ResTable_config tmpConfig = config;
813 const size_t ND = densities.size();
814 for (size_t i=0; i<ND; i++) {
815 tmpConfig.density = densities[i];
816 assets.setConfiguration(tmpConfig);
817 String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
818 if (icon != "") {
819 printf("application-icon-%d:'%s'\n", densities[i], icon.string());
820 }
821 }
822 assets.setConfiguration(config);
823
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700824 String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
825 if (error != "") {
826 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
827 goto bail;
828 }
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700829 int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700830 if (error != "") {
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700831 fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700832 goto bail;
833 }
Dianne Hackborne289bff2011-06-13 19:33:22 -0700834 printf("application: label='%s' ", label.string());
835 printf("icon='%s'\n", icon.string());
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700836 if (testOnly != 0) {
837 printf("testOnly='%d'\n", testOnly);
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -0700838 }
Dan Morrillb6ec11e2012-04-03 12:44:40 -0700839
840 int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0);
841 if (error != "") {
842 fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string());
843 goto bail;
844 }
845 if (debuggable != 0) {
846 printf("application-debuggable\n");
847 }
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700848 } else if (tag == "uses-sdk") {
849 int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
850 if (error != "") {
851 error = "";
852 String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
853 if (error != "") {
854 fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
855 error.string());
856 goto bail;
857 }
Dianne Hackborn723738c2009-06-25 19:48:04 -0700858 if (name == "Donut") targetSdk = 4;
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700859 printf("sdkVersion:'%s'\n", name.string());
860 } else if (code != -1) {
Dianne Hackborn723738c2009-06-25 19:48:04 -0700861 targetSdk = code;
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700862 printf("sdkVersion:'%d'\n", code);
863 }
Suchi Amalapurapu75c49842009-08-14 15:13:09 -0700864 code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1);
865 if (code != -1) {
866 printf("maxSdkVersion:'%d'\n", code);
867 }
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700868 code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
869 if (error != "") {
870 error = "";
871 String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
872 if (error != "") {
873 fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
874 error.string());
875 goto bail;
876 }
Dianne Hackborn723738c2009-06-25 19:48:04 -0700877 if (name == "Donut" && targetSdk < 4) targetSdk = 4;
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700878 printf("targetSdkVersion:'%s'\n", name.string());
879 } else if (code != -1) {
Dianne Hackborn723738c2009-06-25 19:48:04 -0700880 if (targetSdk < code) {
881 targetSdk = code;
882 }
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700883 printf("targetSdkVersion:'%d'\n", code);
884 }
885 } else if (tag == "uses-configuration") {
886 int32_t reqTouchScreen = getIntegerAttribute(tree,
887 REQ_TOUCH_SCREEN_ATTR, NULL, 0);
888 int32_t reqKeyboardType = getIntegerAttribute(tree,
889 REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
890 int32_t reqHardKeyboard = getIntegerAttribute(tree,
891 REQ_HARD_KEYBOARD_ATTR, NULL, 0);
892 int32_t reqNavigation = getIntegerAttribute(tree,
893 REQ_NAVIGATION_ATTR, NULL, 0);
894 int32_t reqFiveWayNav = getIntegerAttribute(tree,
895 REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
Dianne Hackborncb2d50d2010-01-06 11:29:54 -0800896 printf("uses-configuration:");
Dianne Hackbornbb9ea302009-05-18 15:22:00 -0700897 if (reqTouchScreen != 0) {
898 printf(" reqTouchScreen='%d'", reqTouchScreen);
899 }
900 if (reqKeyboardType != 0) {
901 printf(" reqKeyboardType='%d'", reqKeyboardType);
902 }
903 if (reqHardKeyboard != 0) {
904 printf(" reqHardKeyboard='%d'", reqHardKeyboard);
905 }
906 if (reqNavigation != 0) {
907 printf(" reqNavigation='%d'", reqNavigation);
908 }
909 if (reqFiveWayNav != 0) {
910 printf(" reqFiveWayNav='%d'", reqFiveWayNav);
911 }
912 printf("\n");
Dianne Hackborn723738c2009-06-25 19:48:04 -0700913 } else if (tag == "supports-screens") {
914 smallScreen = getIntegerAttribute(tree,
915 SMALL_SCREEN_ATTR, NULL, 1);
916 normalScreen = getIntegerAttribute(tree,
917 NORMAL_SCREEN_ATTR, NULL, 1);
918 largeScreen = getIntegerAttribute(tree,
919 LARGE_SCREEN_ATTR, NULL, 1);
Dianne Hackbornf43489d2010-08-20 12:44:33 -0700920 xlargeScreen = getIntegerAttribute(tree,
921 XLARGE_SCREEN_ATTR, NULL, 1);
Dianne Hackborna0b46c92010-10-21 15:32:06 -0700922 anyDensity = getIntegerAttribute(tree,
923 ANY_DENSITY_ATTR, NULL, 1);
Dianne Hackborne289bff2011-06-13 19:33:22 -0700924 requiresSmallestWidthDp = getIntegerAttribute(tree,
925 REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0);
926 compatibleWidthLimitDp = getIntegerAttribute(tree,
927 COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0);
928 largestWidthLimitDp = getIntegerAttribute(tree,
929 LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0);
Dianne Hackborne5276a72009-08-27 16:28:44 -0700930 } else if (tag == "uses-feature") {
931 String8 name = getAttribute(tree, NAME_ATTR, &error);
Suchi Amalapurapu40b94722009-09-20 13:39:37 -0700932
933 if (name != "" && error == "") {
Dianne Hackborne5276a72009-08-27 16:28:44 -0700934 int req = getIntegerAttribute(tree,
935 REQUIRED_ATTR, NULL, 1);
Dan Morrill89d97c12010-05-03 16:13:14 -0700936
Dianne Hackborne5276a72009-08-27 16:28:44 -0700937 if (name == "android.hardware.camera") {
938 specCameraFeature = true;
Dan Morrill89d97c12010-05-03 16:13:14 -0700939 } else if (name == "android.hardware.camera.autofocus") {
940 // these have no corresponding permission to check for,
941 // but should imply the foundational camera permission
942 reqCameraAutofocusFeature = reqCameraAutofocusFeature || req;
943 specCameraAutofocusFeature = true;
944 } else if (req && (name == "android.hardware.camera.flash")) {
945 // these have no corresponding permission to check for,
946 // but should imply the foundational camera permission
947 reqCameraFlashFeature = true;
948 } else if (name == "android.hardware.location") {
949 specLocationFeature = true;
950 } else if (name == "android.hardware.location.network") {
951 specNetworkLocFeature = true;
952 reqNetworkLocFeature = reqNetworkLocFeature || req;
Dianne Hackbornef05e072010-03-01 17:43:39 -0800953 } else if (name == "android.hardware.location.gps") {
954 specGpsFeature = true;
Dan Morrill89d97c12010-05-03 16:13:14 -0700955 reqGpsFeature = reqGpsFeature || req;
956 } else if (name == "android.hardware.bluetooth") {
957 specBluetoothFeature = true;
958 } else if (name == "android.hardware.touchscreen") {
959 specTouchscreenFeature = true;
960 } else if (name == "android.hardware.touchscreen.multitouch") {
961 specMultitouchFeature = true;
962 } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
963 reqDistinctMultitouchFeature = reqDistinctMultitouchFeature || req;
964 } else if (name == "android.hardware.microphone") {
965 specMicrophoneFeature = true;
966 } else if (name == "android.hardware.wifi") {
967 specWiFiFeature = true;
968 } else if (name == "android.hardware.telephony") {
969 specTelephonyFeature = true;
970 } else if (req && (name == "android.hardware.telephony.gsm" ||
971 name == "android.hardware.telephony.cdma")) {
972 // these have no corresponding permission to check for,
973 // but should imply the foundational telephony permission
974 reqTelephonySubFeature = true;
Dianne Hackborne289bff2011-06-13 19:33:22 -0700975 } else if (name == "android.hardware.screen.portrait") {
976 specScreenPortraitFeature = true;
977 } else if (name == "android.hardware.screen.landscape") {
978 specScreenLandscapeFeature = true;
Dianne Hackborne5276a72009-08-27 16:28:44 -0700979 }
980 printf("uses-feature%s:'%s'\n",
981 req ? "" : "-not-required", name.string());
982 } else {
983 int vers = getIntegerAttribute(tree,
984 GL_ES_VERSION_ATTR, &error);
985 if (error == "") {
986 printf("uses-gl-es:'0x%x'\n", vers);
987 }
988 }
989 } else if (tag == "uses-permission") {
990 String8 name = getAttribute(tree, NAME_ATTR, &error);
Suchi Amalapurapu40b94722009-09-20 13:39:37 -0700991 if (name != "" && error == "") {
Dianne Hackborne5276a72009-08-27 16:28:44 -0700992 if (name == "android.permission.CAMERA") {
993 hasCameraPermission = true;
Dianne Hackbornef05e072010-03-01 17:43:39 -0800994 } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
995 hasGpsPermission = true;
Dan Morrill89d97c12010-05-03 16:13:14 -0700996 } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
997 hasMockLocPermission = true;
998 } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
999 hasCoarseLocPermission = true;
1000 } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
1001 name == "android.permission.INSTALL_LOCATION_PROVIDER") {
1002 hasGeneralLocPermission = true;
1003 } else if (name == "android.permission.BLUETOOTH" ||
1004 name == "android.permission.BLUETOOTH_ADMIN") {
1005 hasBluetoothPermission = true;
1006 } else if (name == "android.permission.RECORD_AUDIO") {
1007 hasRecordAudioPermission = true;
1008 } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
1009 name == "android.permission.CHANGE_WIFI_STATE" ||
1010 name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
1011 hasWiFiPermission = true;
1012 } else if (name == "android.permission.CALL_PHONE" ||
1013 name == "android.permission.CALL_PRIVILEGED" ||
1014 name == "android.permission.MODIFY_PHONE_STATE" ||
1015 name == "android.permission.PROCESS_OUTGOING_CALLS" ||
1016 name == "android.permission.READ_SMS" ||
1017 name == "android.permission.RECEIVE_SMS" ||
1018 name == "android.permission.RECEIVE_MMS" ||
1019 name == "android.permission.RECEIVE_WAP_PUSH" ||
1020 name == "android.permission.SEND_SMS" ||
1021 name == "android.permission.WRITE_APN_SETTINGS" ||
1022 name == "android.permission.WRITE_SMS") {
1023 hasTelephonyPermission = true;
Kenny Root063a44e2011-12-08 08:46:03 -08001024 } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
1025 hasWriteExternalStoragePermission = true;
Dianne Hackborn79245122012-03-12 10:51:26 -07001026 } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
1027 hasReadExternalStoragePermission = true;
Kenny Root063a44e2011-12-08 08:46:03 -08001028 } else if (name == "android.permission.READ_PHONE_STATE") {
1029 hasReadPhoneStatePermission = true;
Dianne Hackborn31b0e0e2012-04-05 19:33:30 -07001030 } else if (name == "android.permission.READ_CONTACTS") {
1031 hasReadContactsPermission = true;
1032 } else if (name == "android.permission.WRITE_CONTACTS") {
1033 hasWriteContactsPermission = true;
1034 } else if (name == "android.permission.READ_CALL_LOG") {
1035 hasReadCallLogPermission = true;
1036 } else if (name == "android.permission.WRITE_CALL_LOG") {
1037 hasWriteCallLogPermission = true;
Dianne Hackborne5276a72009-08-27 16:28:44 -07001038 }
1039 printf("uses-permission:'%s'\n", name.string());
Nick Kralevich1bcc3d62013-04-03 09:00:02 -07001040 int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
1041 if (!req) {
1042 printf("optional-permission:'%s'\n", name.string());
1043 }
Dianne Hackborne5276a72009-08-27 16:28:44 -07001044 } else {
1045 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1046 error.string());
1047 goto bail;
1048 }
Dianne Hackborn43b68032010-09-02 17:14:41 -07001049 } else if (tag == "uses-package") {
1050 String8 name = getAttribute(tree, NAME_ATTR, &error);
1051 if (name != "" && error == "") {
1052 printf("uses-package:'%s'\n", name.string());
1053 } else {
1054 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1055 error.string());
1056 goto bail;
1057 }
Jeff Hamiltone2c17f92010-02-12 13:45:16 -06001058 } else if (tag == "original-package") {
1059 String8 name = getAttribute(tree, NAME_ATTR, &error);
1060 if (name != "" && error == "") {
1061 printf("original-package:'%s'\n", name.string());
1062 } else {
1063 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1064 error.string());
1065 goto bail;
1066 }
Dan Morrill096b67f2010-12-13 16:25:54 -08001067 } else if (tag == "supports-gl-texture") {
Dan Morrill6f51fc12010-10-13 14:33:43 -07001068 String8 name = getAttribute(tree, NAME_ATTR, &error);
1069 if (name != "" && error == "") {
Dan Morrill096b67f2010-12-13 16:25:54 -08001070 printf("supports-gl-texture:'%s'\n", name.string());
Dan Morrill6f51fc12010-10-13 14:33:43 -07001071 } else {
1072 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1073 error.string());
1074 goto bail;
1075 }
Dianne Hackborna0b46c92010-10-21 15:32:06 -07001076 } else if (tag == "compatible-screens") {
1077 printCompatibleScreens(tree);
1078 depth--;
Kenny Root56088a52011-09-29 13:49:45 -07001079 } else if (tag == "package-verifier") {
1080 String8 name = getAttribute(tree, NAME_ATTR, &error);
1081 if (name != "" && error == "") {
1082 String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error);
1083 if (publicKey != "" && error == "") {
1084 printf("package-verifier: name='%s' publicKey='%s'\n",
1085 name.string(), publicKey.string());
1086 }
1087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001089 } else if (depth == 3 && withinApplication) {
1090 withinActivity = false;
1091 withinReceiver = false;
Suchi Amalapurapu1b125982009-08-18 01:42:27 -07001092 withinService = false;
1093 hasIntentFilter = false;
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001094 if(tag == "activity") {
1095 withinActivity = true;
1096 activityName = getAttribute(tree, NAME_ATTR, &error);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 if (error != "") {
1098 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
1099 goto bail;
1100 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001101
1102 activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 if (error != "") {
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001104 fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 goto bail;
1106 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001107
1108 activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1109 if (error != "") {
1110 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
1111 goto bail;
1112 }
Dianne Hackbornf77ae6e2011-06-16 11:11:23 -07001113
1114 int32_t orien = getResolvedIntegerAttribute(&res, tree,
1115 SCREEN_ORIENTATION_ATTR, &error);
1116 if (error == "") {
1117 if (orien == 0 || orien == 6 || orien == 8) {
1118 // Requests landscape, sensorLandscape, or reverseLandscape.
1119 reqScreenLandscapeFeature = true;
1120 } else if (orien == 1 || orien == 7 || orien == 9) {
1121 // Requests portrait, sensorPortrait, or reversePortrait.
1122 reqScreenPortraitFeature = true;
1123 }
1124 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001125 } else if (tag == "uses-library") {
1126 String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
1127 if (error != "") {
1128 fprintf(stderr, "ERROR getting 'android:name' attribute for uses-library: %s\n", error.string());
1129 goto bail;
1130 }
Dianne Hackborn49237342009-08-27 20:08:01 -07001131 int req = getIntegerAttribute(tree,
1132 REQUIRED_ATTR, NULL, 1);
1133 printf("uses-library%s:'%s'\n",
1134 req ? "" : "-not-required", libraryName.string());
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001135 } else if (tag == "receiver") {
1136 withinReceiver = true;
1137 receiverName = getAttribute(tree, NAME_ATTR, &error);
1138
1139 if (error != "") {
1140 fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string());
1141 goto bail;
1142 }
Suchi Amalapurapu1b125982009-08-18 01:42:27 -07001143 } else if (tag == "service") {
1144 withinService = true;
1145 serviceName = getAttribute(tree, NAME_ATTR, &error);
1146
1147 if (error != "") {
1148 fprintf(stderr, "ERROR getting 'android:name' attribute for service: %s\n", error.string());
1149 goto bail;
1150 }
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001151 }
Suchi Amalapurapu1b125982009-08-18 01:42:27 -07001152 } else if ((depth == 4) && (tag == "intent-filter")) {
1153 hasIntentFilter = true;
1154 withinIntentFilter = true;
1155 actMainActivity = actWidgetReceivers = actImeService = actWallpaperService = false;
1156 } else if ((depth == 5) && withinIntentFilter){
1157 String8 action;
1158 if (tag == "action") {
1159 action = getAttribute(tree, NAME_ATTR, &error);
1160 if (error != "") {
1161 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
1162 goto bail;
1163 }
1164 if (withinActivity) {
Dianne Hackbornbb9ea302009-05-18 15:22:00 -07001165 if (action == "android.intent.action.MAIN") {
1166 isMainActivity = true;
Suchi Amalapurapu1b125982009-08-18 01:42:27 -07001167 actMainActivity = true;
Dianne Hackbornbb9ea302009-05-18 15:22:00 -07001168 }
Suchi Amalapurapu1b125982009-08-18 01:42:27 -07001169 } else if (withinReceiver) {
1170 if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
1171 actWidgetReceivers = true;
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001172 }
Suchi Amalapurapu1b125982009-08-18 01:42:27 -07001173 } else if (withinService) {
1174 if (action == "android.view.InputMethod") {
1175 actImeService = true;
1176 } else if (action == "android.service.wallpaper.WallpaperService") {
1177 actWallpaperService = true;
1178 }
1179 }
1180 if (action == "android.intent.action.SEARCH") {
1181 isSearchable = true;
1182 }
1183 }
1184
1185 if (tag == "category") {
1186 String8 category = getAttribute(tree, NAME_ATTR, &error);
1187 if (error != "") {
1188 fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string());
1189 goto bail;
1190 }
1191 if (withinActivity) {
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001192 if (category == "android.intent.category.LAUNCHER") {
1193 isLauncherActivity = true;
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001194 }
1195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 }
1197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 }
Suchi Amalapurapu1b125982009-08-18 01:42:27 -07001199
Kenny Root063a44e2011-12-08 08:46:03 -08001200 // Pre-1.6 implicitly granted permission compatibility logic
1201 if (targetSdk < 4) {
1202 if (!hasWriteExternalStoragePermission) {
1203 printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001204 printf("uses-implied-permission:'android.permission.WRITE_EXTERNAL_STORAGE'," \
1205 "'targetSdkVersion < 4'\n");
Dianne Hackborn79245122012-03-12 10:51:26 -07001206 hasWriteExternalStoragePermission = true;
Kenny Root063a44e2011-12-08 08:46:03 -08001207 }
1208 if (!hasReadPhoneStatePermission) {
1209 printf("uses-permission:'android.permission.READ_PHONE_STATE'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001210 printf("uses-implied-permission:'android.permission.READ_PHONE_STATE'," \
1211 "'targetSdkVersion < 4'\n");
Kenny Root063a44e2011-12-08 08:46:03 -08001212 }
1213 }
1214
Dianne Hackborn79245122012-03-12 10:51:26 -07001215 // If the application has requested WRITE_EXTERNAL_STORAGE, we will
Dianne Hackborn2bd8d042012-06-11 12:27:05 -07001216 // force them to always take READ_EXTERNAL_STORAGE as well. We always
1217 // do this (regardless of target API version) because we can't have
1218 // an app with write permission but not read permission.
Dianne Hackborn79245122012-03-12 10:51:26 -07001219 if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
1220 printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001221 printf("uses-implied-permission:'android.permission.READ_EXTERNAL_STORAGE'," \
1222 "'requested WRITE_EXTERNAL_STORAGE'\n");
Dianne Hackborn79245122012-03-12 10:51:26 -07001223 }
1224
Dianne Hackborn31b0e0e2012-04-05 19:33:30 -07001225 // Pre-JellyBean call log permission compatibility.
1226 if (targetSdk < 16) {
1227 if (!hasReadCallLogPermission && hasReadContactsPermission) {
1228 printf("uses-permission:'android.permission.READ_CALL_LOG'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001229 printf("uses-implied-permission:'android.permission.READ_CALL_LOG'," \
1230 "'targetSdkVersion < 16 and requested READ_CONTACTS'\n");
Dianne Hackborn31b0e0e2012-04-05 19:33:30 -07001231 }
1232 if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
1233 printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001234 printf("uses-implied-permission:'android.permission.WRITE_CALL_LOG'," \
1235 "'targetSdkVersion < 16 and requested WRITE_CONTACTS'\n");
Dianne Hackborn31b0e0e2012-04-05 19:33:30 -07001236 }
1237 }
1238
Dan Morrill89d97c12010-05-03 16:13:14 -07001239 /* The following blocks handle printing "inferred" uses-features, based
1240 * on whether related features or permissions are used by the app.
1241 * Note that the various spec*Feature variables denote whether the
1242 * relevant tag was *present* in the AndroidManfest, not that it was
1243 * present and set to true.
1244 */
1245 // Camera-related back-compatibility logic
1246 if (!specCameraFeature) {
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001247 if (reqCameraFlashFeature) {
Dan Morrill89d97c12010-05-03 16:13:14 -07001248 // if app requested a sub-feature (autofocus or flash) and didn't
1249 // request the base camera feature, we infer that it meant to
1250 printf("uses-feature:'android.hardware.camera'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001251 printf("uses-implied-feature:'android.hardware.camera'," \
1252 "'requested android.hardware.camera.flash feature'\n");
1253 } else if (reqCameraAutofocusFeature) {
1254 // if app requested a sub-feature (autofocus or flash) and didn't
1255 // request the base camera feature, we infer that it meant to
1256 printf("uses-feature:'android.hardware.camera'\n");
1257 printf("uses-implied-feature:'android.hardware.camera'," \
1258 "'requested android.hardware.camera.autofocus feature'\n");
Dan Morrill89d97c12010-05-03 16:13:14 -07001259 } else if (hasCameraPermission) {
1260 // if app wants to use camera but didn't request the feature, we infer
1261 // that it meant to, and further that it wants autofocus
1262 // (which was the 1.0 - 1.5 behavior)
1263 printf("uses-feature:'android.hardware.camera'\n");
1264 if (!specCameraAutofocusFeature) {
1265 printf("uses-feature:'android.hardware.camera.autofocus'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001266 printf("uses-implied-feature:'android.hardware.camera.autofocus'," \
1267 "'requested android.permission.CAMERA permission'\n");
Dan Morrill89d97c12010-05-03 16:13:14 -07001268 }
1269 }
Dianne Hackborne5276a72009-08-27 16:28:44 -07001270 }
Doug Zongkerdbe7a682009-10-09 11:24:51 -07001271
Dan Morrill89d97c12010-05-03 16:13:14 -07001272 // Location-related back-compatibility logic
1273 if (!specLocationFeature &&
1274 (hasMockLocPermission || hasCoarseLocPermission || hasGpsPermission ||
1275 hasGeneralLocPermission || reqNetworkLocFeature || reqGpsFeature)) {
1276 // if app either takes a location-related permission or requests one of the
1277 // sub-features, we infer that it also meant to request the base location feature
1278 printf("uses-feature:'android.hardware.location'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001279 printf("uses-implied-feature:'android.hardware.location'," \
1280 "'requested a location access permission'\n");
Dan Morrill89d97c12010-05-03 16:13:14 -07001281 }
Dianne Hackbornef05e072010-03-01 17:43:39 -08001282 if (!specGpsFeature && hasGpsPermission) {
Dan Morrill89d97c12010-05-03 16:13:14 -07001283 // if app takes GPS (FINE location) perm but does not request the GPS
1284 // feature, we infer that it meant to
Dianne Hackbornef05e072010-03-01 17:43:39 -08001285 printf("uses-feature:'android.hardware.location.gps'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001286 printf("uses-implied-feature:'android.hardware.location.gps'," \
1287 "'requested android.permission.ACCESS_FINE_LOCATION permission'\n");
Dianne Hackbornef05e072010-03-01 17:43:39 -08001288 }
Dan Morrill89d97c12010-05-03 16:13:14 -07001289 if (!specNetworkLocFeature && hasCoarseLocPermission) {
1290 // if app takes Network location (COARSE location) perm but does not request the
1291 // network location feature, we infer that it meant to
1292 printf("uses-feature:'android.hardware.location.network'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001293 printf("uses-implied-feature:'android.hardware.location.network'," \
Dianne Hackbornec559ff2013-02-25 15:42:07 -08001294 "'requested android.permission.ACCESS_COARSE_LOCATION permission'\n");
Dan Morrill89d97c12010-05-03 16:13:14 -07001295 }
1296
1297 // Bluetooth-related compatibility logic
Dan Morrill6b22d812010-06-15 21:41:42 -07001298 if (!specBluetoothFeature && hasBluetoothPermission && (targetSdk > 4)) {
Dan Morrill89d97c12010-05-03 16:13:14 -07001299 // if app takes a Bluetooth permission but does not request the Bluetooth
1300 // feature, we infer that it meant to
1301 printf("uses-feature:'android.hardware.bluetooth'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001302 printf("uses-implied-feature:'android.hardware.bluetooth'," \
1303 "'requested android.permission.BLUETOOTH or android.permission.BLUETOOTH_ADMIN " \
1304 "permission and targetSdkVersion > 4'\n");
Dan Morrill89d97c12010-05-03 16:13:14 -07001305 }
1306
1307 // Microphone-related compatibility logic
1308 if (!specMicrophoneFeature && hasRecordAudioPermission) {
1309 // if app takes the record-audio permission but does not request the microphone
1310 // feature, we infer that it meant to
1311 printf("uses-feature:'android.hardware.microphone'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001312 printf("uses-implied-feature:'android.hardware.microphone'," \
1313 "'requested android.permission.RECORD_AUDIO permission'\n");
Dan Morrill89d97c12010-05-03 16:13:14 -07001314 }
1315
1316 // WiFi-related compatibility logic
1317 if (!specWiFiFeature && hasWiFiPermission) {
1318 // if app takes one of the WiFi permissions but does not request the WiFi
1319 // feature, we infer that it meant to
1320 printf("uses-feature:'android.hardware.wifi'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001321 printf("uses-implied-feature:'android.hardware.wifi'," \
1322 "'requested android.permission.ACCESS_WIFI_STATE, " \
1323 "android.permission.CHANGE_WIFI_STATE, or " \
1324 "android.permission.CHANGE_WIFI_MULTICAST_STATE permission'\n");
Dan Morrill89d97c12010-05-03 16:13:14 -07001325 }
1326
1327 // Telephony-related compatibility logic
1328 if (!specTelephonyFeature && (hasTelephonyPermission || reqTelephonySubFeature)) {
1329 // if app takes one of the telephony permissions or requests a sub-feature but
1330 // does not request the base telephony feature, we infer that it meant to
1331 printf("uses-feature:'android.hardware.telephony'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001332 printf("uses-implied-feature:'android.hardware.telephony'," \
1333 "'requested a telephony-related permission or feature'\n");
Dan Morrill89d97c12010-05-03 16:13:14 -07001334 }
1335
1336 // Touchscreen-related back-compatibility logic
1337 if (!specTouchscreenFeature) { // not a typo!
1338 // all apps are presumed to require a touchscreen, unless they explicitly say
1339 // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
1340 // Note that specTouchscreenFeature is true if the tag is present, regardless
1341 // of whether its value is true or false, so this is safe
1342 printf("uses-feature:'android.hardware.touchscreen'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001343 printf("uses-implied-feature:'android.hardware.touchscreen'," \
1344 "'assumed you require a touch screen unless explicitly made optional'\n");
Dan Morrill89d97c12010-05-03 16:13:14 -07001345 }
1346 if (!specMultitouchFeature && reqDistinctMultitouchFeature) {
1347 // if app takes one of the telephony permissions or requests a sub-feature but
1348 // does not request the base telephony feature, we infer that it meant to
1349 printf("uses-feature:'android.hardware.touchscreen.multitouch'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001350 printf("uses-implied-feature:'android.hardware.touchscreen.multitouch'," \
1351 "'requested android.hardware.touchscreen.multitouch.distinct feature'\n");
Dan Morrill89d97c12010-05-03 16:13:14 -07001352 }
Dianne Hackbornef05e072010-03-01 17:43:39 -08001353
Dianne Hackborne289bff2011-06-13 19:33:22 -07001354 // Landscape/portrait-related compatibility logic
Dianne Hackbornf77ae6e2011-06-16 11:11:23 -07001355 if (!specScreenLandscapeFeature && !specScreenPortraitFeature) {
1356 // If the app has specified any activities in its manifest
1357 // that request a specific orientation, then assume that
1358 // orientation is required.
1359 if (reqScreenLandscapeFeature) {
1360 printf("uses-feature:'android.hardware.screen.landscape'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001361 printf("uses-implied-feature:'android.hardware.screen.landscape'," \
1362 "'one or more activities have specified a landscape orientation'\n");
Dianne Hackbornf77ae6e2011-06-16 11:11:23 -07001363 }
1364 if (reqScreenPortraitFeature) {
1365 printf("uses-feature:'android.hardware.screen.portrait'\n");
Dianne Hackborn4aa14b92012-04-13 19:18:41 -07001366 printf("uses-implied-feature:'android.hardware.screen.portrait'," \
1367 "'one or more activities have specified a portrait orientation'\n");
Dianne Hackbornf77ae6e2011-06-16 11:11:23 -07001368 }
Dianne Hackborne289bff2011-06-13 19:33:22 -07001369 }
1370
Suchi Amalapurapu1b125982009-08-18 01:42:27 -07001371 if (hasMainActivity) {
1372 printf("main\n");
1373 }
1374 if (hasWidgetReceivers) {
1375 printf("app-widget\n");
1376 }
1377 if (hasImeService) {
1378 printf("ime\n");
1379 }
1380 if (hasWallpaperService) {
1381 printf("wallpaper\n");
1382 }
1383 if (hasOtherActivities) {
1384 printf("other-activities\n");
1385 }
1386 if (isSearchable) {
1387 printf("search\n");
1388 }
1389 if (hasOtherReceivers) {
1390 printf("other-receivers\n");
1391 }
1392 if (hasOtherServices) {
1393 printf("other-services\n");
1394 }
1395
Dianne Hackborne289bff2011-06-13 19:33:22 -07001396 // For modern apps, if screen size buckets haven't been specified
1397 // but the new width ranges have, then infer the buckets from them.
1398 if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
1399 && requiresSmallestWidthDp > 0) {
1400 int compatWidth = compatibleWidthLimitDp;
1401 if (compatWidth <= 0) compatWidth = requiresSmallestWidthDp;
1402 if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
1403 smallScreen = -1;
1404 } else {
1405 smallScreen = 0;
1406 }
1407 if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
1408 normalScreen = -1;
1409 } else {
1410 normalScreen = 0;
1411 }
1412 if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
1413 largeScreen = -1;
1414 } else {
1415 largeScreen = 0;
1416 }
1417 if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
1418 xlargeScreen = -1;
1419 } else {
1420 xlargeScreen = 0;
1421 }
1422 }
1423
Dianne Hackborn723738c2009-06-25 19:48:04 -07001424 // Determine default values for any unspecified screen sizes,
1425 // based on the target SDK of the package. As of 4 (donut)
1426 // the screen size support was introduced, so all default to
1427 // enabled.
1428 if (smallScreen > 0) {
1429 smallScreen = targetSdk >= 4 ? -1 : 0;
1430 }
1431 if (normalScreen > 0) {
1432 normalScreen = -1;
1433 }
1434 if (largeScreen > 0) {
1435 largeScreen = targetSdk >= 4 ? -1 : 0;
1436 }
Dianne Hackbornf43489d2010-08-20 12:44:33 -07001437 if (xlargeScreen > 0) {
Scott Maind58fb972010-11-04 18:32:00 -07001438 // Introduced in Gingerbread.
1439 xlargeScreen = targetSdk >= 9 ? -1 : 0;
Dianne Hackbornf43489d2010-08-20 12:44:33 -07001440 }
Dianne Hackborna0b46c92010-10-21 15:32:06 -07001441 if (anyDensity > 0) {
Dianne Hackborne289bff2011-06-13 19:33:22 -07001442 anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
1443 || compatibleWidthLimitDp > 0) ? -1 : 0;
Dianne Hackborna0b46c92010-10-21 15:32:06 -07001444 }
Dianne Hackborn723738c2009-06-25 19:48:04 -07001445 printf("supports-screens:");
1446 if (smallScreen != 0) printf(" 'small'");
1447 if (normalScreen != 0) printf(" 'normal'");
1448 if (largeScreen != 0) printf(" 'large'");
Dianne Hackbornf43489d2010-08-20 12:44:33 -07001449 if (xlargeScreen != 0) printf(" 'xlarge'");
Dianne Hackborn723738c2009-06-25 19:48:04 -07001450 printf("\n");
Dianne Hackborna0b46c92010-10-21 15:32:06 -07001451 printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
Dianne Hackborne289bff2011-06-13 19:33:22 -07001452 if (requiresSmallestWidthDp > 0) {
1453 printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
1454 }
1455 if (compatibleWidthLimitDp > 0) {
1456 printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
1457 }
1458 if (largestWidthLimitDp > 0) {
1459 printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
1460 }
Dianne Hackborna0b46c92010-10-21 15:32:06 -07001461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 printf("locales:");
Dianne Hackborne17086b2009-06-19 15:13:28 -07001463 const size_t NL = locales.size();
1464 for (size_t i=0; i<NL; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 const char* localeStr = locales[i].string();
1466 if (localeStr == NULL || strlen(localeStr) == 0) {
1467 localeStr = "--_--";
1468 }
1469 printf(" '%s'", localeStr);
1470 }
1471 printf("\n");
Suchi Amalapurapu1b125982009-08-18 01:42:27 -07001472
Dianne Hackborne17086b2009-06-19 15:13:28 -07001473 printf("densities:");
1474 const size_t ND = densities.size();
1475 for (size_t i=0; i<ND; i++) {
1476 printf(" '%d'", densities[i]);
1477 }
1478 printf("\n");
Suchi Amalapurapu1b125982009-08-18 01:42:27 -07001479
Dianne Hackbornbb9ea302009-05-18 15:22:00 -07001480 AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
1481 if (dir != NULL) {
1482 if (dir->getFileCount() > 0) {
1483 printf("native-code:");
1484 for (size_t i=0; i<dir->getFileCount(); i++) {
1485 printf(" '%s'", dir->getFileName(i).string());
1486 }
1487 printf("\n");
1488 }
1489 delete dir;
1490 }
Dan Morrille74763e2012-01-06 10:47:10 -08001491 } else if (strcmp("badger", option) == 0) {
Dianne Hackborn6c997a92012-01-31 11:27:43 -08001492 printf("%s", CONSOLE_DATA);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 } else if (strcmp("configurations", option) == 0) {
1494 Vector<ResTable_config> configs;
1495 res.getConfigurations(&configs);
1496 const size_t N = configs.size();
1497 for (size_t i=0; i<N; i++) {
1498 printf("%s\n", configs[i].toString().string());
1499 }
1500 } else {
1501 fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
1502 goto bail;
1503 }
1504 }
1505
1506 result = NO_ERROR;
Suchi Amalapurapu7ef189d2009-04-02 15:20:29 -07001507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001508bail:
1509 if (asset) {
1510 delete asset;
1511 }
1512 return (result != NO_ERROR);
1513}
1514
1515
1516/*
1517 * Handle the "add" command, which wants to add files to a new or
1518 * pre-existing archive.
1519 */
1520int doAdd(Bundle* bundle)
1521{
1522 ZipFile* zip = NULL;
1523 status_t result = UNKNOWN_ERROR;
1524 const char* zipFileName;
1525
1526 if (bundle->getUpdate()) {
1527 /* avoid confusion */
1528 fprintf(stderr, "ERROR: can't use '-u' with add\n");
1529 goto bail;
1530 }
1531
1532 if (bundle->getFileSpecCount() < 1) {
1533 fprintf(stderr, "ERROR: must specify zip file name\n");
1534 goto bail;
1535 }
1536 zipFileName = bundle->getFileSpecEntry(0);
1537
1538 if (bundle->getFileSpecCount() < 2) {
1539 fprintf(stderr, "NOTE: nothing to do\n");
1540 goto bail;
1541 }
1542
1543 zip = openReadWrite(zipFileName, true);
1544 if (zip == NULL) {
1545 fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
1546 goto bail;
1547 }
1548
1549 for (int i = 1; i < bundle->getFileSpecCount(); i++) {
1550 const char* fileName = bundle->getFileSpecEntry(i);
1551
1552 if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
1553 printf(" '%s'... (from gzip)\n", fileName);
1554 result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
1555 } else {
Doug Zongkerdbe7a682009-10-09 11:24:51 -07001556 if (bundle->getJunkPath()) {
1557 String8 storageName = String8(fileName).getPathLeaf();
1558 printf(" '%s' as '%s'...\n", fileName, storageName.string());
1559 result = zip->add(fileName, storageName.string(),
1560 bundle->getCompressionMethod(), NULL);
1561 } else {
1562 printf(" '%s'...\n", fileName);
1563 result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
1564 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 }
1566 if (result != NO_ERROR) {
1567 fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
1568 if (result == NAME_NOT_FOUND)
1569 fprintf(stderr, ": file not found\n");
1570 else if (result == ALREADY_EXISTS)
1571 fprintf(stderr, ": already exists in archive\n");
1572 else
1573 fprintf(stderr, "\n");
1574 goto bail;
1575 }
1576 }
1577
1578 result = NO_ERROR;
1579
1580bail:
1581 delete zip;
1582 return (result != NO_ERROR);
1583}
1584
1585
1586/*
1587 * Delete files from an existing archive.
1588 */
1589int doRemove(Bundle* bundle)
1590{
1591 ZipFile* zip = NULL;
1592 status_t result = UNKNOWN_ERROR;
1593 const char* zipFileName;
1594
1595 if (bundle->getFileSpecCount() < 1) {
1596 fprintf(stderr, "ERROR: must specify zip file name\n");
1597 goto bail;
1598 }
1599 zipFileName = bundle->getFileSpecEntry(0);
1600
1601 if (bundle->getFileSpecCount() < 2) {
1602 fprintf(stderr, "NOTE: nothing to do\n");
1603 goto bail;
1604 }
1605
1606 zip = openReadWrite(zipFileName, false);
1607 if (zip == NULL) {
1608 fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
1609 zipFileName);
1610 goto bail;
1611 }
1612
1613 for (int i = 1; i < bundle->getFileSpecCount(); i++) {
1614 const char* fileName = bundle->getFileSpecEntry(i);
1615 ZipEntry* entry;
1616
1617 entry = zip->getEntryByName(fileName);
1618 if (entry == NULL) {
1619 printf(" '%s' NOT FOUND\n", fileName);
1620 continue;
1621 }
1622
1623 result = zip->remove(entry);
1624
1625 if (result != NO_ERROR) {
1626 fprintf(stderr, "Unable to delete '%s' from '%s'\n",
1627 bundle->getFileSpecEntry(i), zipFileName);
1628 goto bail;
1629 }
1630 }
1631
1632 /* update the archive */
1633 zip->flush();
1634
1635bail:
1636 delete zip;
1637 return (result != NO_ERROR);
1638}
1639
1640
1641/*
1642 * Package up an asset directory and associated application files.
1643 */
1644int doPackage(Bundle* bundle)
1645{
1646 const char* outputAPKFile;
1647 int retVal = 1;
1648 status_t err;
1649 sp<AaptAssets> assets;
1650 int N;
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001651 FILE* fp;
1652 String8 dependencyFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653
1654 // -c zz_ZZ means do pseudolocalization
1655 ResourceFilter filter;
1656 err = filter.parse(bundle->getConfigurations());
1657 if (err != NO_ERROR) {
1658 goto bail;
1659 }
1660 if (filter.containsPseudo()) {
1661 bundle->setPseudolocalize(true);
1662 }
1663
1664 N = bundle->getFileSpecCount();
1665 if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
1666 && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) {
1667 fprintf(stderr, "ERROR: no input files\n");
1668 goto bail;
1669 }
1670
1671 outputAPKFile = bundle->getOutputAPKFile();
1672
1673 // Make sure the filenames provided exist and are of the appropriate type.
1674 if (outputAPKFile) {
1675 FileType type;
1676 type = getFileType(outputAPKFile);
1677 if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
1678 fprintf(stderr,
1679 "ERROR: output file '%s' exists but is not regular file\n",
1680 outputAPKFile);
1681 goto bail;
1682 }
1683 }
1684
1685 // Load the assets.
1686 assets = new AaptAssets();
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001687
Josiah Gaskin03589cc2011-06-27 16:26:02 -07001688 // Set up the resource gathering in assets if we're going to generate
Josiah Gaskinb711f3f2011-08-15 18:33:44 -07001689 // dependency files. Every time we encounter a resource while slurping
1690 // the tree, we'll add it to these stores so we have full resource paths
1691 // to write to a dependency file.
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001692 if (bundle->getGenDependencies()) {
Josiah Gaskin03589cc2011-06-27 16:26:02 -07001693 sp<FilePathStore> resPathStore = new FilePathStore;
1694 assets->setFullResPaths(resPathStore);
1695 sp<FilePathStore> assetPathStore = new FilePathStore;
1696 assets->setFullAssetPaths(assetPathStore);
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001697 }
1698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 err = assets->slurpFromArgs(bundle);
1700 if (err < 0) {
1701 goto bail;
1702 }
1703
1704 if (bundle->getVerbose()) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001705 assets->print(String8());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 }
1707
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001708 // If they asked for any fileAs that need to be compiled, do so.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
1710 err = buildResources(bundle, assets);
1711 if (err != 0) {
1712 goto bail;
1713 }
1714 }
1715
1716 // At this point we've read everything and processed everything. From here
1717 // on out it's just writing output files.
1718 if (SourcePos::hasErrors()) {
1719 goto bail;
1720 }
1721
Dianne Hackborn1644c6d2012-02-06 15:33:21 -08001722 // Update symbols with information about which ones are needed as Java symbols.
1723 assets->applyJavaSymbols();
1724 if (SourcePos::hasErrors()) {
1725 goto bail;
1726 }
1727
Josiah Gaskinb711f3f2011-08-15 18:33:44 -07001728 // If we've been asked to generate a dependency file, do that here
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001729 if (bundle->getGenDependencies()) {
Josiah Gaskinb711f3f2011-08-15 18:33:44 -07001730 // If this is the packaging step, generate the dependency file next to
1731 // the output apk (e.g. bin/resources.ap_.d)
Josiah Gaskin03589cc2011-06-27 16:26:02 -07001732 if (outputAPKFile) {
1733 dependencyFile = String8(outputAPKFile);
Josiah Gaskinb711f3f2011-08-15 18:33:44 -07001734 // Add the .d extension to the dependency file.
Josiah Gaskin03589cc2011-06-27 16:26:02 -07001735 dependencyFile.append(".d");
1736 } else {
Josiah Gaskinb711f3f2011-08-15 18:33:44 -07001737 // Else if this is the R.java dependency generation step,
1738 // generate the dependency file in the R.java package subdirectory
1739 // e.g. gen/com/foo/app/R.java.d
Josiah Gaskin03589cc2011-06-27 16:26:02 -07001740 dependencyFile = String8(bundle->getRClassDir());
Josiah Gaskinb711f3f2011-08-15 18:33:44 -07001741 dependencyFile.appendPath("R.java.d");
Josiah Gaskin03589cc2011-06-27 16:26:02 -07001742 }
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001743 // Make sure we have a clean dependency file to start with
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001744 fp = fopen(dependencyFile, "w");
1745 fclose(fp);
1746 }
1747
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 // Write out R.java constants
Dianne Hackborn1644c6d2012-02-06 15:33:21 -08001749 if (!assets->havePrivateSymbols()) {
Xavier Ducrohet63459ad2009-11-30 18:05:10 -08001750 if (bundle->getCustomPackage() == NULL) {
Josiah Gaskinb711f3f2011-08-15 18:33:44 -07001751 // Write the R.java file into the appropriate class directory
1752 // e.g. gen/com/foo/app/R.java
Xavier Ducrohet63459ad2009-11-30 18:05:10 -08001753 err = writeResourceSymbols(bundle, assets, assets->getPackage(), true);
1754 } else {
1755 const String8 customPkg(bundle->getCustomPackage());
1756 err = writeResourceSymbols(bundle, assets, customPkg, true);
1757 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 if (err < 0) {
1759 goto bail;
1760 }
Ying Wang002f5372012-04-25 18:53:49 -07001761 // If we have library files, we're going to write our R.java file into
1762 // the appropriate class directory for those libraries as well.
1763 // e.g. gen/com/foo/app/lib/R.java
1764 if (bundle->getExtraPackages() != NULL) {
1765 // Split on colon
1766 String8 libs(bundle->getExtraPackages());
1767 char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
1768 while (packageString != NULL) {
1769 // Write the R.java file out with the correct package name
1770 err = writeResourceSymbols(bundle, assets, String8(packageString), true);
1771 if (err < 0) {
1772 goto bail;
1773 }
1774 packageString = strtok(NULL, ":");
1775 }
1776 libs.unlockBuffer();
1777 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 } else {
1779 err = writeResourceSymbols(bundle, assets, assets->getPackage(), false);
1780 if (err < 0) {
1781 goto bail;
1782 }
1783 err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true);
1784 if (err < 0) {
1785 goto bail;
1786 }
1787 }
1788
Joe Onorato1553c822009-08-30 13:36:22 -07001789 // Write out the ProGuard file
1790 err = writeProguardFile(bundle, assets);
1791 if (err < 0) {
1792 goto bail;
1793 }
1794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 // Write the apk
1796 if (outputAPKFile) {
1797 err = writeAPK(bundle, assets, String8(outputAPKFile));
1798 if (err != NO_ERROR) {
1799 fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputAPKFile);
1800 goto bail;
1801 }
1802 }
1803
Josiah Gaskinb711f3f2011-08-15 18:33:44 -07001804 // If we've been asked to generate a dependency file, we need to finish up here.
1805 // the writeResourceSymbols and writeAPK functions have already written the target
1806 // half of the dependency file, now we need to write the prerequisites. (files that
1807 // the R.java file or .ap_ file depend on)
Josiah Gaskin03589cc2011-06-27 16:26:02 -07001808 if (bundle->getGenDependencies()) {
1809 // Now that writeResourceSymbols or writeAPK has taken care of writing
1810 // the targets to our dependency file, we'll write the prereqs
1811 fp = fopen(dependencyFile, "a+");
1812 fprintf(fp, " : ");
1813 bool includeRaw = (outputAPKFile != NULL);
1814 err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
Josiah Gaskinb711f3f2011-08-15 18:33:44 -07001815 // Also manually add the AndroidManifeset since it's not under res/ or assets/
1816 // and therefore was not added to our pathstores during slurping
Josiah Gaskin03589cc2011-06-27 16:26:02 -07001817 fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
1818 fclose(fp);
1819 }
1820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 retVal = 0;
1822bail:
1823 if (SourcePos::hasErrors()) {
1824 SourcePos::printErrors(stderr);
1825 }
1826 return retVal;
1827}
Josiah Gaskin8a39da82011-06-06 17:00:35 -07001828
1829/*
1830 * Do PNG Crunching
1831 * PRECONDITIONS
1832 * -S flag points to a source directory containing drawable* folders
1833 * -C flag points to destination directory. The folder structure in the
1834 * source directory will be mirrored to the destination (cache) directory
1835 *
1836 * POSTCONDITIONS
1837 * Destination directory will be updated to match the PNG files in
1838 * the source directory.
1839 */
1840int doCrunch(Bundle* bundle)
1841{
1842 fprintf(stdout, "Crunching PNG Files in ");
1843 fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
1844 fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
1845
1846 updatePreProcessedCache(bundle);
1847
1848 return NO_ERROR;
1849}
Dan Morrille74763e2012-01-06 10:47:10 -08001850
Xavier Ducrohetb1f6ad82012-12-21 09:54:02 -08001851/*
1852 * Do PNG Crunching on a single flag
1853 * -i points to a single png file
1854 * -o points to a single png output file
1855 */
1856int doSingleCrunch(Bundle* bundle)
1857{
1858 fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
1859 fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
1860
1861 String8 input(bundle->getSingleCrunchInputFile());
1862 String8 output(bundle->getSingleCrunchOutputFile());
Xavier Ducrohetb7de2192013-01-15 16:41:29 -08001863
Xavier Ducrohetc75d3f52013-01-14 18:02:40 -08001864 if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
1865 // we can't return the status_t as it gets truncate to the lower 8 bits.
1866 return 42;
1867 }
Xavier Ducrohetb7de2192013-01-15 16:41:29 -08001868
Xavier Ducrohetc75d3f52013-01-14 18:02:40 -08001869 return NO_ERROR;
Xavier Ducrohetb1f6ad82012-12-21 09:54:02 -08001870}
1871
Dan Morrille74763e2012-01-06 10:47:10 -08001872char CONSOLE_DATA[2925] = {
1873 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1874 32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1875 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1876 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
1877 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
1878 86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
1879 62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1880 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1881 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
1882 81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
1883 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
1884 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1885 32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
1886 59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1887 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1888 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
1889 59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
1890 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1891 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1892 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
1893 58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
1894 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
1895 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
1896 47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
1897 121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1898 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1899 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
1900 81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
1901 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
1902 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1903 32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
1904 59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1905 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1906 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
1907 59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
1908 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1909 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1910 32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
1911 70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
1912 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
1913 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1914 32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
1915 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1916 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1917 32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
1918 81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
1919 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
1920 32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
1921 59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
1922 60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1923 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
1924 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
1925 61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
1926 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1927 32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
1928 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
1929 109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
1930 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
1931 67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
1932 59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
1933 61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
1934 32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
1935 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
1936 73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
1937 59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
1938 32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
1939 59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
1940 46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
1941 97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
1942 46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
1943 119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
1944 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
1945 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1946 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
1947 119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
1948 59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
1949 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1950 32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
1951 81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
1952 87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
1953 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
1954 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
1955 45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
1956 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1957 32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
1958 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
1959 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
1960 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
1961 59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
1962 59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1963 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1964 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
1965 81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
1966 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1967 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1968 32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
1969 81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1970 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
1971 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
1972 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
1973 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1974 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1975 32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
1976 81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
1977 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
1978 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1979 58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
1980 61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1981 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1982 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
1983 81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
1984 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1985 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1986 32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
1987 81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1988 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
1989 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
1990 59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
1991 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1992 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1993 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
1994 58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
1995 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
1996 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
1997 61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
1998 59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
1999 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
2000 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
2001 32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
2002 61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2003 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2004 32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
2005 59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
2006 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
2007 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
2008 59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
2009 59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2010 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2011 32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2012 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2013 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2014 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2015 46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
2016 46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2017 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2018 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
2019 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
2020 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2021 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2022 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
2023 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
2024 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2025 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
2026 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
2027 59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2028 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2029 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
2030 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
2031 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2032 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2033 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2034 32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2035 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10
2036 };