1 //
2 // Copyright 2006 The Android Open Source Project
3 //
4 // Android Asset Packaging Tool main entry point.
5 //
6 #include "AaptXml.h"
7 #include "ApkBuilder.h"
8 #include "Bundle.h"
9 #include "Images.h"
10 #include "Main.h"
11 #include "ResourceFilter.h"
12 #include "ResourceTable.h"
13 #include "XMLNode.h"
14
15 #include <androidfw/PathUtils.h>
16 #include <utils/Errors.h>
17 #include <utils/KeyedVector.h>
18 #include <utils/List.h>
19 #include <utils/Log.h>
20 #include <utils/SortedVector.h>
21 #include <utils/threads.h>
22 #include <utils/Vector.h>
23
24 #include <errno.h>
25 #include <fcntl.h>
26
27 #include <iostream>
28 #include <string>
29 #include <sstream>
30
31 using namespace android;
32
33 /*
34 * Open the file read only. The call fails if the file doesn't exist.
35 *
36 * Returns NULL on failure.
37 */
openReadOnly(const char * fileName)38 ZipFile* openReadOnly(const char* fileName)
39 {
40 ZipFile* zip;
41 status_t result;
42
43 zip = new ZipFile;
44 result = zip->open(fileName, ZipFile::kOpenReadOnly);
45 if (result != NO_ERROR) {
46 if (result == NAME_NOT_FOUND) {
47 fprintf(stderr, "ERROR: '%s' not found\n", fileName);
48 } else if (result == PERMISSION_DENIED) {
49 fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
50 } else {
51 fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
52 fileName);
53 }
54 delete zip;
55 return NULL;
56 }
57
58 return zip;
59 }
60
61 /*
62 * Open the file read-write. The file will be created if it doesn't
63 * already exist and "okayToCreate" is set.
64 *
65 * Returns NULL on failure.
66 */
openReadWrite(const char * fileName,bool okayToCreate)67 ZipFile* openReadWrite(const char* fileName, bool okayToCreate)
68 {
69 ZipFile* zip = NULL;
70 status_t result;
71 int flags;
72
73 flags = ZipFile::kOpenReadWrite;
74 if (okayToCreate) {
75 flags |= ZipFile::kOpenCreate;
76 }
77
78 zip = new ZipFile;
79 result = zip->open(fileName, flags);
80 if (result != NO_ERROR) {
81 delete zip;
82 zip = NULL;
83 goto bail;
84 }
85
86 bail:
87 return zip;
88 }
89
90
91 /*
92 * Return a short string describing the compression method.
93 */
compressionName(int method)94 const char* compressionName(int method)
95 {
96 if (method == ZipEntry::kCompressStored) {
97 return "Stored";
98 } else if (method == ZipEntry::kCompressDeflated) {
99 return "Deflated";
100 } else {
101 return "Unknown";
102 }
103 }
104
105 /*
106 * Return the percent reduction in size (0% == no compression).
107 */
calcPercent(long uncompressedLen,long compressedLen)108 int 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 /*
118 * Handle the "list" command, which can be a simple file dump or
119 * a verbose listing.
120 *
121 * The verbose listing closely matches the output of the Info-ZIP "unzip"
122 * command.
123 */
doList(Bundle * bundle)124 int doList(Bundle* bundle)
125 {
126 int result = 1;
127 ZipFile* zip = NULL;
128 const ZipEntry* entry;
129 long totalUncLen, totalCompLen;
130 const char* zipFileName;
131
132 if (bundle->getFileSpecCount() != 1) {
133 fprintf(stderr, "ERROR: specify zip file name (only)\n");
134 goto bail;
135 }
136 zipFileName = bundle->getFileSpecEntry(0);
137
138 zip = openReadOnly(zipFileName);
139 if (zip == NULL) {
140 goto bail;
141 }
142
143 int count, i;
144
145 if (bundle->getVerbose()) {
146 printf("Archive: %s\n", zipFileName);
147 printf(
148 " Length Method Size Ratio Offset Date Time CRC-32 Name\n");
149 printf(
150 "-------- ------ ------- ----- ------- ---- ---- ------ ----\n");
151 }
152
153 totalUncLen = totalCompLen = 0;
154
155 count = zip->getNumEntries();
156 for (i = 0; i < count; i++) {
157 entry = zip->getEntryByIndex(i);
158 if (bundle->getVerbose()) {
159 char dateBuf[32];
160 time_t when;
161
162 when = entry->getModWhen();
163 strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
164 localtime(&when));
165
166 printf("%8ld %-7.7s %7ld %3d%% %8zd %s %08lx %s\n",
167 (long) entry->getUncompressedLen(),
168 compressionName(entry->getCompressionMethod()),
169 (long) entry->getCompressedLen(),
170 calcPercent(entry->getUncompressedLen(),
171 entry->getCompressedLen()),
172 (size_t) entry->getLFHOffset(),
173 dateBuf,
174 entry->getCRC32(),
175 entry->getFileName());
176 } else {
177 printf("%s\n", entry->getFileName());
178 }
179
180 totalUncLen += entry->getUncompressedLen();
181 totalCompLen += entry->getCompressedLen();
182 }
183
184 if (bundle->getVerbose()) {
185 printf(
186 "-------- ------- --- -------\n");
187 printf("%8ld %7ld %2d%% %d files\n",
188 totalUncLen,
189 totalCompLen,
190 calcPercent(totalUncLen, totalCompLen),
191 zip->getNumEntries());
192 }
193
194 if (bundle->getAndroidList()) {
195 AssetManager assets;
196 if (!assets.addAssetPath(String8(zipFileName), NULL)) {
197 fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
198 goto bail;
199 }
200
201 #ifdef __ANDROID__
202 static const bool kHaveAndroidOs = true;
203 #else
204 static const bool kHaveAndroidOs = false;
205 #endif
206 const ResTable& res = assets.getResources(false);
207 if (!kHaveAndroidOs) {
208 printf("\nResource table:\n");
209 res.print(false);
210 }
211
212 Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
213 Asset::ACCESS_BUFFER);
214 if (manifestAsset == NULL) {
215 printf("\nNo AndroidManifest.xml found.\n");
216 } else {
217 printf("\nAndroid manifest:\n");
218 ResXMLTree tree;
219 tree.setTo(manifestAsset->getBuffer(true),
220 manifestAsset->getLength());
221 printXMLBlock(&tree);
222 }
223 delete manifestAsset;
224 }
225
226 result = 0;
227
228 bail:
229 delete zip;
230 return result;
231 }
232
printResolvedResourceAttribute(const ResTable & resTable,const ResXMLTree & tree,uint32_t attrRes,const String8 & attrLabel,String8 * outError)233 static void printResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree,
234 uint32_t attrRes, const String8& attrLabel, String8* outError)
235 {
236 Res_value value;
237 AaptXml::getResolvedResourceAttribute(resTable, tree, attrRes, &value, outError);
238 if (*outError != "") {
239 *outError = "error print resolved resource attribute";
240 return;
241 }
242 if (value.dataType == Res_value::TYPE_STRING) {
243 String8 result = AaptXml::getResolvedAttribute(resTable, tree, attrRes, outError);
244 printf("%s='%s'", attrLabel.c_str(),
245 ResTable::normalizeForOutput(result.c_str()).c_str());
246 } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
247 value.dataType <= Res_value::TYPE_LAST_INT) {
248 printf("%s='%d'", attrLabel.c_str(), value.data);
249 } else {
250 printf("%s='0x%x'", attrLabel.c_str(), (int)value.data);
251 }
252 }
253
254 // These are attribute resource constants for the platform, as found
255 // in android.R.attr
256 enum {
257 LABEL_ATTR = 0x01010001,
258 ICON_ATTR = 0x01010002,
259 NAME_ATTR = 0x01010003,
260 PERMISSION_ATTR = 0x01010006,
261 EXPORTED_ATTR = 0x01010010,
262 GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
263 RESOURCE_ATTR = 0x01010025,
264 DEBUGGABLE_ATTR = 0x0101000f,
265 VALUE_ATTR = 0x01010024,
266 VERSION_CODE_ATTR = 0x0101021b,
267 VERSION_NAME_ATTR = 0x0101021c,
268 SCREEN_ORIENTATION_ATTR = 0x0101001e,
269 MIN_SDK_VERSION_ATTR = 0x0101020c,
270 MAX_SDK_VERSION_ATTR = 0x01010271,
271 REQ_TOUCH_SCREEN_ATTR = 0x01010227,
272 REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
273 REQ_HARD_KEYBOARD_ATTR = 0x01010229,
274 REQ_NAVIGATION_ATTR = 0x0101022a,
275 REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
276 TARGET_SDK_VERSION_ATTR = 0x01010270,
277 TEST_ONLY_ATTR = 0x01010272,
278 ANY_DENSITY_ATTR = 0x0101026c,
279 GL_ES_VERSION_ATTR = 0x01010281,
280 SMALL_SCREEN_ATTR = 0x01010284,
281 NORMAL_SCREEN_ATTR = 0x01010285,
282 LARGE_SCREEN_ATTR = 0x01010286,
283 XLARGE_SCREEN_ATTR = 0x010102bf,
284 REQUIRED_ATTR = 0x0101028e,
285 INSTALL_LOCATION_ATTR = 0x010102b7,
286 SCREEN_SIZE_ATTR = 0x010102ca,
287 SCREEN_DENSITY_ATTR = 0x010102cb,
288 REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
289 COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
290 LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
291 PUBLIC_KEY_ATTR = 0x010103a6,
292 CATEGORY_ATTR = 0x010103e8,
293 BANNER_ATTR = 0x10103f2,
294 ISGAME_ATTR = 0x10103f4,
295 REQUIRED_FEATURE_ATTR = 0x1010557,
296 REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
297 COMPILE_SDK_VERSION_ATTR = 0x01010572, // NOT FINALIZED
298 COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573, // NOT FINALIZED
299 };
300
getComponentName(String8 & pkgName,String8 & componentName)301 String8 getComponentName(String8 &pkgName, String8 &componentName) {
302 ssize_t idx = componentName.find(".");
303 String8 retStr(pkgName);
304 if (idx == 0) {
305 retStr += componentName;
306 } else if (idx < 0) {
307 retStr += ".";
308 retStr += componentName;
309 } else {
310 return componentName;
311 }
312 return retStr;
313 }
314
printCompatibleScreens(ResXMLTree & tree,String8 * outError)315 static void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
316 size_t len;
317 ResXMLTree::event_code_t code;
318 int depth = 0;
319 bool first = true;
320 printf("compatible-screens:");
321 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
322 if (code == ResXMLTree::END_TAG) {
323 depth--;
324 if (depth < 0) {
325 break;
326 }
327 continue;
328 }
329 if (code != ResXMLTree::START_TAG) {
330 continue;
331 }
332 depth++;
333 const char16_t* ctag16 = tree.getElementName(&len);
334 if (ctag16 == NULL) {
335 *outError = "failed to get XML element name (bad string pool)";
336 return;
337 }
338 String8 tag(ctag16);
339 if (tag == "screen") {
340 int32_t screenSize = AaptXml::getIntegerAttribute(tree,
341 SCREEN_SIZE_ATTR);
342 int32_t screenDensity = AaptXml::getIntegerAttribute(tree,
343 SCREEN_DENSITY_ATTR);
344 if (screenSize > 0 && screenDensity > 0) {
345 if (!first) {
346 printf(",");
347 }
348 first = false;
349 printf("'%d/%d'", screenSize, screenDensity);
350 }
351 }
352 }
353 printf("\n");
354 }
355
printUsesPermission(const String8 & name,bool optional=false,int maxSdkVersion=-1,const String8 & requiredFeature=String8 (),const String8 & requiredNotFeature=String8 ())356 static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1,
357 const String8& requiredFeature = String8(),
358 const String8& requiredNotFeature = String8()) {
359 printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.c_str()).c_str());
360 if (maxSdkVersion != -1) {
361 printf(" maxSdkVersion='%d'", maxSdkVersion);
362 }
363 if (requiredFeature.length() > 0) {
364 printf(" requiredFeature='%s'", requiredFeature.c_str());
365 }
366 if (requiredNotFeature.length() > 0) {
367 printf(" requiredNotFeature='%s'", requiredNotFeature.c_str());
368 }
369 printf("\n");
370
371 if (optional) {
372 printf("optional-permission: name='%s'",
373 ResTable::normalizeForOutput(name.c_str()).c_str());
374 if (maxSdkVersion != -1) {
375 printf(" maxSdkVersion='%d'", maxSdkVersion);
376 }
377 printf("\n");
378 }
379 }
380
printUsesPermissionSdk23(const String8 & name,int maxSdkVersion=-1)381 static void printUsesPermissionSdk23(const String8& name, int maxSdkVersion=-1) {
382 printf("uses-permission-sdk-23: ");
383
384 printf("name='%s'", ResTable::normalizeForOutput(name.c_str()).c_str());
385 if (maxSdkVersion != -1) {
386 printf(" maxSdkVersion='%d'", maxSdkVersion);
387 }
388 printf("\n");
389 }
390
printUsesImpliedPermission(const String8 & name,const String8 & reason,const int32_t maxSdkVersion=-1)391 static void printUsesImpliedPermission(const String8& name, const String8& reason,
392 const int32_t maxSdkVersion = -1) {
393 printf("uses-implied-permission: name='%s'",
394 ResTable::normalizeForOutput(name.c_str()).c_str());
395 if (maxSdkVersion != -1) {
396 printf(" maxSdkVersion='%d'", maxSdkVersion);
397 }
398 printf(" reason='%s'\n", ResTable::normalizeForOutput(reason.c_str()).c_str());
399 }
400
getNfcAidCategories(AssetManager & assets,const String8 & xmlPath,bool offHost,String8 * outError=NULL)401 Vector<String8> getNfcAidCategories(AssetManager& assets, const String8& xmlPath, bool offHost,
402 String8 *outError = NULL)
403 {
404 Asset* aidAsset = assets.openNonAsset(xmlPath.c_str(), Asset::ACCESS_BUFFER);
405 if (aidAsset == NULL) {
406 if (outError != NULL) *outError = "xml resource does not exist";
407 return Vector<String8>();
408 }
409
410 const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
411
412 bool withinApduService = false;
413 Vector<String8> categories;
414
415 String8 error;
416 ResXMLTree tree;
417 tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
418
419 size_t len;
420 int depth = 0;
421 ResXMLTree::event_code_t code;
422 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
423 if (code == ResXMLTree::END_TAG) {
424 depth--;
425 const char16_t* ctag16 = tree.getElementName(&len);
426 if (ctag16 == NULL) {
427 *outError = "failed to get XML element name (bad string pool)";
428 return Vector<String8>();
429 }
430 String8 tag(ctag16);
431
432 if (depth == 0 && tag == serviceTagName) {
433 withinApduService = false;
434 }
435
436 } else if (code == ResXMLTree::START_TAG) {
437 depth++;
438 const char16_t* ctag16 = tree.getElementName(&len);
439 if (ctag16 == NULL) {
440 *outError = "failed to get XML element name (bad string pool)";
441 return Vector<String8>();
442 }
443 String8 tag(ctag16);
444
445 if (depth == 1) {
446 if (tag == serviceTagName) {
447 withinApduService = true;
448 }
449 } else if (depth == 2 && withinApduService) {
450 if (tag == "aid-group") {
451 String8 category = AaptXml::getAttribute(tree, CATEGORY_ATTR, &error);
452 if (error != "") {
453 if (outError != NULL) *outError = error;
454 return Vector<String8>();
455 }
456
457 categories.add(category);
458 }
459 }
460 }
461 }
462 aidAsset->close();
463 return categories;
464 }
465
printComponentPresence(const char * componentName)466 static void printComponentPresence(const char* componentName) {
467 printf("provides-component:'%s'\n", componentName);
468 }
469
470 /**
471 * Represents a feature that has been automatically added due to
472 * a pre-requisite or some other reason.
473 */
474 struct ImpliedFeature {
ImpliedFeatureImpliedFeature475 ImpliedFeature() : impliedBySdk23(false) {}
ImpliedFeatureImpliedFeature476 ImpliedFeature(const String8& n, bool sdk23) : name(n), impliedBySdk23(sdk23) {}
477
478 /**
479 * Name of the implied feature.
480 */
481 String8 name;
482
483 /**
484 * Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)?
485 */
486 bool impliedBySdk23;
487
488 /**
489 * List of human-readable reasons for why this feature was implied.
490 */
491 SortedVector<String8> reasons;
492 };
493
494 struct Feature {
FeatureFeature495 Feature() : required(false), version(-1) {}
FeatureFeature496 explicit Feature(bool required, int32_t version = -1) : required(required), version(version) {}
497
498 /**
499 * Whether the feature is required.
500 */
501 bool required;
502
503 /**
504 * What version of the feature is requested.
505 */
506 int32_t version;
507 };
508
509 /**
510 * Represents a <feature-group> tag in the AndroidManifest.xml
511 */
512 struct FeatureGroup {
FeatureGroupFeatureGroup513 FeatureGroup() : openGLESVersion(-1) {}
514
515 /**
516 * Human readable label
517 */
518 String8 label;
519
520 /**
521 * Explicit features defined in the group
522 */
523 KeyedVector<String8, Feature> features;
524
525 /**
526 * OpenGL ES version required
527 */
528 int openGLESVersion;
529 };
530
hasFeature(const char * name,const FeatureGroup & grp,const KeyedVector<String8,ImpliedFeature> & implied)531 static bool hasFeature(const char* name, const FeatureGroup& grp,
532 const KeyedVector<String8, ImpliedFeature>& implied) {
533 String8 name8(name);
534 ssize_t idx = grp.features.indexOfKey(name8);
535 if (idx < 0) {
536 idx = implied.indexOfKey(name8);
537 }
538 return idx >= 0;
539 }
540
addImpliedFeature(KeyedVector<String8,ImpliedFeature> * impliedFeatures,const char * name,const String8 & reason,bool sdk23)541 static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
542 const char* name, const String8& reason, bool sdk23) {
543 String8 name8(name);
544 ssize_t idx = impliedFeatures->indexOfKey(name8);
545 if (idx < 0) {
546 idx = impliedFeatures->add(name8, ImpliedFeature(name8, sdk23));
547 }
548
549 ImpliedFeature* feature = &impliedFeatures->editValueAt(idx);
550
551 // A non-sdk 23 implied feature takes precedence.
552 if (feature->impliedBySdk23 && !sdk23) {
553 feature->impliedBySdk23 = false;
554 }
555 feature->reasons.add(reason);
556 }
557
printFeatureGroupImpl(const FeatureGroup & grp,const KeyedVector<String8,ImpliedFeature> * impliedFeatures)558 static void printFeatureGroupImpl(const FeatureGroup& grp,
559 const KeyedVector<String8, ImpliedFeature>* impliedFeatures) {
560 printf("feature-group: label='%s'\n", grp.label.c_str());
561
562 if (grp.openGLESVersion > 0) {
563 printf(" uses-gl-es: '0x%x'\n", grp.openGLESVersion);
564 }
565
566 const size_t numFeatures = grp.features.size();
567 for (size_t i = 0; i < numFeatures; i++) {
568 const Feature& feature = grp.features[i];
569 const bool required = feature.required;
570 const int32_t version = feature.version;
571
572 const String8& featureName = grp.features.keyAt(i);
573 printf(" uses-feature%s: name='%s'", (required ? "" : "-not-required"),
574 ResTable::normalizeForOutput(featureName.c_str()).c_str());
575
576 if (version > 0) {
577 printf(" version='%d'", version);
578 }
579 printf("\n");
580 }
581
582 const size_t numImpliedFeatures =
583 (impliedFeatures != NULL) ? impliedFeatures->size() : 0;
584 for (size_t i = 0; i < numImpliedFeatures; i++) {
585 const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i);
586 if (grp.features.indexOfKey(impliedFeature.name) >= 0) {
587 // The feature is explicitly set, no need to use implied
588 // definition.
589 continue;
590 }
591
592 String8 printableFeatureName(ResTable::normalizeForOutput(
593 impliedFeature.name.c_str()));
594 const char* sdk23Suffix = impliedFeature.impliedBySdk23 ? "-sdk-23" : "";
595
596 printf(" uses-feature%s: name='%s'\n", sdk23Suffix, printableFeatureName.c_str());
597 printf(" uses-implied-feature%s: name='%s' reason='", sdk23Suffix,
598 printableFeatureName.c_str());
599 const size_t numReasons = impliedFeature.reasons.size();
600 for (size_t j = 0; j < numReasons; j++) {
601 printf("%s", impliedFeature.reasons[j].c_str());
602 if (j + 2 < numReasons) {
603 printf(", ");
604 } else if (j + 1 < numReasons) {
605 printf(", and ");
606 }
607 }
608 printf("'\n");
609 }
610 }
611
printFeatureGroup(const FeatureGroup & grp)612 static void printFeatureGroup(const FeatureGroup& grp) {
613 printFeatureGroupImpl(grp, NULL);
614 }
615
printDefaultFeatureGroup(const FeatureGroup & grp,const KeyedVector<String8,ImpliedFeature> & impliedFeatures)616 static void printDefaultFeatureGroup(const FeatureGroup& grp,
617 const KeyedVector<String8, ImpliedFeature>& impliedFeatures) {
618 printFeatureGroupImpl(grp, &impliedFeatures);
619 }
620
addParentFeatures(FeatureGroup * grp,const String8 & name)621 static void addParentFeatures(FeatureGroup* grp, const String8& name) {
622 if (name == "android.hardware.camera.autofocus" ||
623 name == "android.hardware.camera.flash") {
624 grp->features.add(String8("android.hardware.camera"), Feature(true));
625 } else if (name == "android.hardware.location.gps" ||
626 name == "android.hardware.location.network") {
627 grp->features.add(String8("android.hardware.location"), Feature(true));
628 } else if (name == "android.hardware.faketouch.multitouch") {
629 grp->features.add(String8("android.hardware.faketouch"), Feature(true));
630 } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
631 name == "android.hardware.faketouch.multitouch.jazzhands") {
632 grp->features.add(String8("android.hardware.faketouch.multitouch"), Feature(true));
633 grp->features.add(String8("android.hardware.faketouch"), Feature(true));
634 } else if (name == "android.hardware.touchscreen.multitouch") {
635 grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
636 } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
637 name == "android.hardware.touchscreen.multitouch.jazzhands") {
638 grp->features.add(String8("android.hardware.touchscreen.multitouch"), Feature(true));
639 grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
640 } else if (name == "android.hardware.opengles.aep") {
641 const int openGLESVersion31 = 0x00030001;
642 if (openGLESVersion31 > grp->openGLESVersion) {
643 grp->openGLESVersion = openGLESVersion31;
644 }
645 }
646 }
647
addImpliedFeaturesForPermission(const int targetSdk,const String8 & name,KeyedVector<String8,ImpliedFeature> * impliedFeatures,bool impliedBySdk23Permission)648 static void addImpliedFeaturesForPermission(const int targetSdk, const String8& name,
649 KeyedVector<String8, ImpliedFeature>* impliedFeatures,
650 bool impliedBySdk23Permission) {
651 if (name == "android.permission.CAMERA") {
652 addImpliedFeature(impliedFeatures, "android.hardware.camera",
653 String8::format("requested %s permission", name.c_str()),
654 impliedBySdk23Permission);
655 } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
656 if (targetSdk < SDK_LOLLIPOP) {
657 addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
658 String8::format("requested %s permission", name.c_str()),
659 impliedBySdk23Permission);
660 addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
661 String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
662 impliedBySdk23Permission);
663 }
664 addImpliedFeature(impliedFeatures, "android.hardware.location",
665 String8::format("requested %s permission", name.c_str()),
666 impliedBySdk23Permission);
667 } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
668 if (targetSdk < SDK_LOLLIPOP) {
669 addImpliedFeature(impliedFeatures, "android.hardware.location.network",
670 String8::format("requested %s permission", name.c_str()),
671 impliedBySdk23Permission);
672 addImpliedFeature(impliedFeatures, "android.hardware.location.network",
673 String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
674 impliedBySdk23Permission);
675 }
676 addImpliedFeature(impliedFeatures, "android.hardware.location",
677 String8::format("requested %s permission", name.c_str()),
678 impliedBySdk23Permission);
679 } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
680 name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
681 name == "android.permission.INSTALL_LOCATION_PROVIDER") {
682 addImpliedFeature(impliedFeatures, "android.hardware.location",
683 String8::format("requested %s permission", name.c_str()),
684 impliedBySdk23Permission);
685 } else if (name == "android.permission.BLUETOOTH" ||
686 name == "android.permission.BLUETOOTH_ADMIN") {
687 if (targetSdk > SDK_DONUT) {
688 addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
689 String8::format("requested %s permission", name.c_str()),
690 impliedBySdk23Permission);
691 addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
692 String8::format("targetSdkVersion > %d", SDK_DONUT),
693 impliedBySdk23Permission);
694 }
695 } else if (name == "android.permission.RECORD_AUDIO") {
696 addImpliedFeature(impliedFeatures, "android.hardware.microphone",
697 String8::format("requested %s permission", name.c_str()),
698 impliedBySdk23Permission);
699 } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
700 name == "android.permission.CHANGE_WIFI_STATE" ||
701 name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
702 addImpliedFeature(impliedFeatures, "android.hardware.wifi",
703 String8::format("requested %s permission", name.c_str()),
704 impliedBySdk23Permission);
705 } else if (name == "android.permission.CALL_PHONE" ||
706 name == "android.permission.CALL_PRIVILEGED" ||
707 name == "android.permission.MODIFY_PHONE_STATE" ||
708 name == "android.permission.PROCESS_OUTGOING_CALLS" ||
709 name == "android.permission.READ_SMS" ||
710 name == "android.permission.RECEIVE_SMS" ||
711 name == "android.permission.RECEIVE_MMS" ||
712 name == "android.permission.RECEIVE_WAP_PUSH" ||
713 name == "android.permission.SEND_SMS" ||
714 name == "android.permission.WRITE_APN_SETTINGS" ||
715 name == "android.permission.WRITE_SMS") {
716 addImpliedFeature(impliedFeatures, "android.hardware.telephony",
717 String8("requested a telephony permission"),
718 impliedBySdk23Permission);
719 }
720 }
721
722 /*
723 * Handle the "dump" command, to extract select data from an archive.
724 */
725 extern char CONSOLE_DATA[2925]; // see EOF
doDump(Bundle * bundle)726 int doDump(Bundle* bundle)
727 {
728 status_t result = UNKNOWN_ERROR;
729
730 if (bundle->getFileSpecCount() < 1) {
731 fprintf(stderr, "ERROR: no dump option specified\n");
732 return 1;
733 }
734
735 if (bundle->getFileSpecCount() < 2) {
736 fprintf(stderr, "ERROR: no dump file specified\n");
737 return 1;
738 }
739
740 const char* option = bundle->getFileSpecEntry(0);
741 const char* filename = bundle->getFileSpecEntry(1);
742
743 AssetManager assets;
744 int32_t assetsCookie;
745
746 // Add any dependencies passed in.
747 for (size_t i = 0; i < bundle->getPackageIncludes().size(); i++) {
748 const String8& assetPath = bundle->getPackageIncludes()[i];
749 if (!assets.addAssetPath(assetPath, NULL)) {
750 fprintf(stderr, "ERROR: included asset path %s could not be loaded\n", assetPath.c_str());
751 return 1;
752 }
753 }
754
755 if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
756 fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
757 return 1;
758 }
759
760 // Make a dummy config for retrieving resources... we need to supply
761 // non-default values for some configs so that we can retrieve resources
762 // in the app that don't have a default. The most important of these is
763 // the API version because key resources like icons will have an implicit
764 // version if they are using newer config types like density.
765 ResTable_config config;
766 memset(&config, 0, sizeof(ResTable_config));
767 config.language[0] = 'e';
768 config.language[1] = 'n';
769 config.country[0] = 'U';
770 config.country[1] = 'S';
771 config.orientation = ResTable_config::ORIENTATION_PORT;
772 config.density = ResTable_config::DENSITY_MEDIUM;
773 config.sdkVersion = SDK_CUR_DEVELOPMENT; // Very high.
774 config.screenWidthDp = 320;
775 config.screenHeightDp = 480;
776 config.smallestScreenWidthDp = 320;
777 config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL;
778 assets.setConfiguration(config);
779
780 const ResTable& res = assets.getResources(false);
781 if (res.getError() != NO_ERROR) {
782 fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
783 return 1;
784 }
785
786 // Source for AndroidManifest.xml
787 const String8 manifestFile("AndroidManifest.xml");
788
789 // The dynamicRefTable can be null if there are no resources for this asset cookie.
790 // This fine.
791 auto noop_destructor = [](const DynamicRefTable* /*ref_table */) { };
792 auto dynamicRefTable = std::shared_ptr<const DynamicRefTable>(
793 res.getDynamicRefTableForCookie(assetsCookie), noop_destructor);
794
795 Asset* asset = NULL;
796
797 if (strcmp("resources", option) == 0) {
798 #ifndef __ANDROID__
799 res.print(bundle->getValues());
800 #endif
801
802 } else if (strcmp("strings", option) == 0) {
803 const ResStringPool* pool = res.getTableStringBlock(0);
804 printStringPool(pool);
805
806 } else if (strcmp("xmltree", option) == 0) {
807 if (bundle->getFileSpecCount() < 3) {
808 fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
809 goto bail;
810 }
811
812 for (int i=2; i<bundle->getFileSpecCount(); i++) {
813 const char* resname = bundle->getFileSpecEntry(i);
814 ResXMLTree tree(dynamicRefTable);
815 asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
816 if (asset == NULL) {
817 fprintf(stderr, "ERROR: dump failed because resource %s not found\n", resname);
818 goto bail;
819 }
820
821 if (tree.setTo(asset->getBuffer(true),
822 asset->getLength()) != NO_ERROR) {
823 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
824 goto bail;
825 }
826 tree.restart();
827 printXMLBlock(&tree);
828 tree.uninit();
829 delete asset;
830 asset = NULL;
831 }
832
833 } else if (strcmp("xmlstrings", option) == 0) {
834 if (bundle->getFileSpecCount() < 3) {
835 fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
836 goto bail;
837 }
838
839 for (int i=2; i<bundle->getFileSpecCount(); i++) {
840 const char* resname = bundle->getFileSpecEntry(i);
841 asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
842 if (asset == NULL) {
843 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
844 goto bail;
845 }
846
847 ResXMLTree tree(dynamicRefTable);
848 if (tree.setTo(asset->getBuffer(true),
849 asset->getLength()) != NO_ERROR) {
850 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
851 goto bail;
852 }
853 printStringPool(&tree.getStrings());
854 delete asset;
855 asset = NULL;
856 }
857
858 } else {
859 asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER);
860 if (asset == NULL) {
861 fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
862 goto bail;
863 }
864
865 ResXMLTree tree(dynamicRefTable);
866 if (tree.setTo(asset->getBuffer(true),
867 asset->getLength()) != NO_ERROR) {
868 fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
869 goto bail;
870 }
871 tree.restart();
872
873 if (strcmp("permissions", option) == 0) {
874 size_t len;
875 ResXMLTree::event_code_t code;
876 int depth = 0;
877 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
878 code != ResXMLTree::BAD_DOCUMENT) {
879 if (code == ResXMLTree::END_TAG) {
880 depth--;
881 continue;
882 }
883 if (code != ResXMLTree::START_TAG) {
884 continue;
885 }
886 depth++;
887 const char16_t* ctag16 = tree.getElementName(&len);
888 if (ctag16 == NULL) {
889 SourcePos(manifestFile, tree.getLineNumber()).error(
890 "ERROR: failed to get XML element name (bad string pool)");
891 goto bail;
892 }
893 String8 tag(ctag16);
894 //printf("Depth %d tag %s\n", depth, tag.c_str());
895 if (depth == 1) {
896 if (tag != "manifest") {
897 SourcePos(manifestFile, tree.getLineNumber()).error(
898 "ERROR: manifest does not start with <manifest> tag");
899 goto bail;
900 }
901 String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
902 printf("package: %s\n", ResTable::normalizeForOutput(pkg.c_str()).c_str());
903 } else if (depth == 2) {
904 if (tag == "permission") {
905 String8 error;
906 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
907 if (error != "") {
908 SourcePos(manifestFile, tree.getLineNumber()).error(
909 "ERROR getting 'android:name': %s", error.c_str());
910 goto bail;
911 }
912
913 if (name == "") {
914 SourcePos(manifestFile, tree.getLineNumber()).error(
915 "ERROR: missing 'android:name' for permission");
916 goto bail;
917 }
918 printf("permission: %s\n",
919 ResTable::normalizeForOutput(name.c_str()).c_str());
920 } else if (tag == "uses-permission") {
921 String8 error;
922 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
923 if (error != "") {
924 SourcePos(manifestFile, tree.getLineNumber()).error(
925 "ERROR getting 'android:name' attribute: %s", error.c_str());
926 goto bail;
927 }
928
929 if (name == "") {
930 SourcePos(manifestFile, tree.getLineNumber()).error(
931 "ERROR: missing 'android:name' for uses-permission");
932 goto bail;
933 }
934 printUsesPermission(name,
935 AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
936 AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
937 } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
938 String8 error;
939 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
940 if (error != "") {
941 SourcePos(manifestFile, tree.getLineNumber()).error(
942 "ERROR getting 'android:name' attribute: %s", error.c_str());
943 goto bail;
944 }
945
946 if (name == "") {
947 SourcePos(manifestFile, tree.getLineNumber()).error(
948 "ERROR: missing 'android:name' for uses-permission-sdk-23");
949 goto bail;
950 }
951 printUsesPermissionSdk23(
952 name,
953 AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
954 }
955 }
956 }
957 } else if (strcmp("badging", option) == 0) {
958 Vector<String8> locales;
959 res.getLocales(&locales);
960
961 Vector<ResTable_config> configs;
962 res.getConfigurations(&configs);
963 SortedVector<int> densities;
964 const size_t NC = configs.size();
965 for (size_t i=0; i<NC; i++) {
966 int dens = configs[i].density;
967 if (dens == 0) {
968 dens = 160;
969 }
970 densities.add(dens);
971 }
972
973 std::vector<ResXMLParser::ResXMLPosition> tagsToSkip;
974
975 size_t len;
976 ResXMLTree::event_code_t code;
977 int depth = 0;
978 String8 error;
979 bool withinActivity = false;
980 bool isMainActivity = false;
981 bool isLauncherActivity = false;
982 bool isLeanbackLauncherActivity = false;
983 bool isSearchable = false;
984 bool withinApplication = false;
985 bool withinSupportsInput = false;
986 bool withinFeatureGroup = false;
987 bool withinReceiver = false;
988 bool withinService = false;
989 bool withinProvider = false;
990 bool withinIntentFilter = false;
991 bool hasMainActivity = false;
992 bool hasOtherActivities = false;
993 bool hasOtherReceivers = false;
994 bool hasOtherServices = false;
995 bool hasIntentFilter = false;
996
997 bool hasWallpaperService = false;
998 bool hasImeService = false;
999 bool hasAccessibilityService = false;
1000 bool hasPrintService = false;
1001 bool hasWidgetReceivers = false;
1002 bool hasDeviceAdminReceiver = false;
1003 bool hasPaymentService = false;
1004 bool hasDocumentsProvider = false;
1005 bool hasCameraActivity = false;
1006 bool hasCameraSecureActivity = false;
1007 bool hasLauncher = false;
1008 bool hasNotificationListenerService = false;
1009 bool hasDreamService = false;
1010
1011 bool actMainActivity = false;
1012 bool actWidgetReceivers = false;
1013 bool actDeviceAdminEnabled = false;
1014 bool actImeService = false;
1015 bool actWallpaperService = false;
1016 bool actAccessibilityService = false;
1017 bool actPrintService = false;
1018 bool actHostApduService = false;
1019 bool actOffHostApduService = false;
1020 bool actDocumentsProvider = false;
1021 bool actNotificationListenerService = false;
1022 bool actDreamService = false;
1023 bool actCamera = false;
1024 bool actCameraSecure = false;
1025 bool catLauncher = false;
1026 bool hasMetaHostPaymentCategory = false;
1027 bool hasMetaOffHostPaymentCategory = false;
1028
1029 // These permissions are required by services implementing services
1030 // the system binds to (IME, Accessibility, PrintServices, etc.)
1031 bool hasBindDeviceAdminPermission = false;
1032 bool hasBindAccessibilityServicePermission = false;
1033 bool hasBindPrintServicePermission = false;
1034 bool hasBindNfcServicePermission = false;
1035 bool hasRequiredSafAttributes = false;
1036 bool hasBindNotificationListenerServicePermission = false;
1037 bool hasBindDreamServicePermission = false;
1038
1039 // These two implement the implicit permissions that are granted
1040 // to pre-1.6 applications.
1041 bool hasWriteExternalStoragePermission = false;
1042 int32_t writeExternalStoragePermissionMaxSdkVersion = -1;
1043 bool hasReadPhoneStatePermission = false;
1044
1045 // If an app requests write storage, they will also get read storage.
1046 bool hasReadExternalStoragePermission = false;
1047
1048 // Implement transition to read and write call log.
1049 bool hasReadContactsPermission = false;
1050 bool hasWriteContactsPermission = false;
1051 bool hasReadCallLogPermission = false;
1052 bool hasWriteCallLogPermission = false;
1053
1054 // If an app declares itself as multiArch, we report the
1055 // native libraries differently.
1056 bool hasMultiArch = false;
1057
1058 // This next group of variables is used to implement a group of
1059 // backward-compatibility heuristics necessitated by the addition of
1060 // some new uses-feature constants in 2.1 and 2.2. In most cases, the
1061 // heuristic is "if an app requests a permission but doesn't explicitly
1062 // request the corresponding <uses-feature>, presume it's there anyway".
1063
1064 // 2.2 also added some other features that apps can request, but that
1065 // have no corresponding permission, so we cannot implement any
1066 // back-compatibility heuristic for them. The below are thus unnecessary
1067 // (but are retained here for documentary purposes.)
1068 //bool specCompassFeature = false;
1069 //bool specAccelerometerFeature = false;
1070 //bool specProximityFeature = false;
1071 //bool specAmbientLightFeature = false;
1072 //bool specLiveWallpaperFeature = false;
1073
1074 int targetSdk = 0;
1075 int smallScreen = 1;
1076 int normalScreen = 1;
1077 int largeScreen = 1;
1078 int xlargeScreen = 1;
1079 int anyDensity = 1;
1080 int requiresSmallestWidthDp = 0;
1081 int compatibleWidthLimitDp = 0;
1082 int largestWidthLimitDp = 0;
1083 String8 pkg;
1084 String8 activityName;
1085 String8 activityLabel;
1086 String8 activityIcon;
1087 String8 activityBanner;
1088 String8 receiverName;
1089 String8 serviceName;
1090 Vector<String8> supportedInput;
1091
1092 FeatureGroup commonFeatures;
1093 Vector<FeatureGroup> featureGroups;
1094 KeyedVector<String8, ImpliedFeature> impliedFeatures;
1095
1096 {
1097 int curDepth = 0;
1098 ResXMLParser::ResXMLPosition initialPos;
1099 tree.getPosition(&initialPos);
1100
1101 // Find all of the "uses-sdk" tags within the "manifest" tag.
1102 std::vector<ResXMLParser::ResXMLPosition> usesSdkTagPositions;
1103 ResXMLParser::ResXMLPosition curPos;
1104 while ((code = tree.next()) != ResXMLTree::END_DOCUMENT &&
1105 code != ResXMLTree::BAD_DOCUMENT) {
1106 if (code == ResXMLTree::END_TAG) {
1107 curDepth--;
1108 continue;
1109 }
1110 if (code == ResXMLTree::START_TAG) {
1111 curDepth++;
1112 }
1113 const char16_t* ctag16 = tree.getElementName(&len);
1114 if (ctag16 == NULL || String8(ctag16) != "uses-sdk" || curDepth != 2) {
1115 continue;
1116 }
1117
1118 tree.getPosition(&curPos);
1119 usesSdkTagPositions.emplace_back(curPos);
1120 }
1121
1122 // Skip all "uses-sdk" tags besides the very last tag. The android runtime only uses
1123 // the attribute values from the last defined tag.
1124 for (size_t i = 1; i < usesSdkTagPositions.size(); i++) {
1125 tagsToSkip.emplace_back(usesSdkTagPositions[i - 1]);
1126 }
1127
1128 // Reset the position before parsing.
1129 tree.setPosition(initialPos);
1130 }
1131
1132 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
1133 code != ResXMLTree::BAD_DOCUMENT) {
1134 if (code == ResXMLTree::END_TAG) {
1135 depth--;
1136 if (depth < 2) {
1137 if (withinSupportsInput && !supportedInput.empty()) {
1138 printf("supports-input: '");
1139 const size_t N = supportedInput.size();
1140 for (size_t i=0; i<N; i++) {
1141 printf("%s", ResTable::normalizeForOutput(
1142 supportedInput[i].c_str()).c_str());
1143 if (i != N - 1) {
1144 printf("' '");
1145 } else {
1146 printf("'\n");
1147 }
1148 }
1149 supportedInput.clear();
1150 }
1151 withinApplication = false;
1152 withinSupportsInput = false;
1153 withinFeatureGroup = false;
1154 } else if (depth < 3) {
1155 if (withinActivity && isMainActivity) {
1156 String8 aName(getComponentName(pkg, activityName));
1157 if (isLauncherActivity) {
1158 printf("launchable-activity:");
1159 if (aName.length() > 0) {
1160 printf(" name='%s' ",
1161 ResTable::normalizeForOutput(aName.c_str()).c_str());
1162 }
1163 printf(" label='%s' icon='%s'\n",
1164 ResTable::normalizeForOutput(activityLabel.c_str())
1165 .c_str(),
1166 ResTable::normalizeForOutput(activityIcon.c_str())
1167 .c_str());
1168 }
1169 if (isLeanbackLauncherActivity) {
1170 printf("leanback-launchable-activity:");
1171 if (aName.length() > 0) {
1172 printf(" name='%s' ",
1173 ResTable::normalizeForOutput(aName.c_str()).c_str());
1174 }
1175 printf(" label='%s' icon='%s' banner='%s'\n",
1176 ResTable::normalizeForOutput(activityLabel.c_str())
1177 .c_str(),
1178 ResTable::normalizeForOutput(activityIcon.c_str())
1179 .c_str(),
1180 ResTable::normalizeForOutput(activityBanner.c_str())
1181 .c_str());
1182 }
1183 }
1184 if (!hasIntentFilter) {
1185 hasOtherActivities |= withinActivity;
1186 hasOtherReceivers |= withinReceiver;
1187 hasOtherServices |= withinService;
1188 } else {
1189 if (withinService) {
1190 hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
1191 hasBindNfcServicePermission);
1192 hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
1193 hasBindNfcServicePermission);
1194 }
1195 }
1196 withinActivity = false;
1197 withinService = false;
1198 withinReceiver = false;
1199 withinProvider = false;
1200 hasIntentFilter = false;
1201 isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false;
1202 } else if (depth < 4) {
1203 if (withinIntentFilter) {
1204 if (withinActivity) {
1205 hasMainActivity |= actMainActivity;
1206 hasLauncher |= catLauncher;
1207 hasCameraActivity |= actCamera;
1208 hasCameraSecureActivity |= actCameraSecure;
1209 hasOtherActivities |=
1210 !actMainActivity && !actCamera && !actCameraSecure;
1211 } else if (withinReceiver) {
1212 hasWidgetReceivers |= actWidgetReceivers;
1213 hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
1214 hasBindDeviceAdminPermission);
1215 hasOtherReceivers |=
1216 (!actWidgetReceivers && !actDeviceAdminEnabled);
1217 } else if (withinService) {
1218 hasImeService |= actImeService;
1219 hasWallpaperService |= actWallpaperService;
1220 hasAccessibilityService |= (actAccessibilityService &&
1221 hasBindAccessibilityServicePermission);
1222 hasPrintService |=
1223 (actPrintService && hasBindPrintServicePermission);
1224 hasNotificationListenerService |= actNotificationListenerService &&
1225 hasBindNotificationListenerServicePermission;
1226 hasDreamService |= actDreamService && hasBindDreamServicePermission;
1227 hasOtherServices |= (!actImeService && !actWallpaperService &&
1228 !actAccessibilityService && !actPrintService &&
1229 !actHostApduService && !actOffHostApduService &&
1230 !actNotificationListenerService);
1231 } else if (withinProvider) {
1232 hasDocumentsProvider |=
1233 actDocumentsProvider && hasRequiredSafAttributes;
1234 }
1235 }
1236 withinIntentFilter = false;
1237 }
1238 continue;
1239 }
1240 if (code != ResXMLTree::START_TAG) {
1241 continue;
1242 }
1243
1244 depth++;
1245
1246 // If this tag should be skipped, skip to the end of this tag.
1247 ResXMLParser::ResXMLPosition curPos;
1248 tree.getPosition(&curPos);
1249 if (std::find(tagsToSkip.begin(), tagsToSkip.end(), curPos) != tagsToSkip.end()) {
1250 const int breakDepth = depth - 1;
1251 while ((code = tree.next()) != ResXMLTree::END_DOCUMENT &&
1252 code != ResXMLTree::BAD_DOCUMENT) {
1253 if (code == ResXMLTree::END_TAG && --depth == breakDepth) {
1254 break;
1255 } else if (code == ResXMLTree::START_TAG) {
1256 depth++;
1257 }
1258 }
1259 continue;
1260 }
1261
1262 const char16_t* ctag16 = tree.getElementName(&len);
1263 if (ctag16 == NULL) {
1264 SourcePos(manifestFile, tree.getLineNumber()).error(
1265 "ERROR: failed to get XML element name (bad string pool)");
1266 goto bail;
1267 }
1268 String8 tag(ctag16);
1269 //printf("Depth %d, %s\n", depth, tag.c_str());
1270 if (depth == 1) {
1271 if (tag != "manifest") {
1272 SourcePos(manifestFile, tree.getLineNumber()).error(
1273 "ERROR: manifest does not start with <manifest> tag");
1274 goto bail;
1275 }
1276 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
1277 printf("package: name='%s' ",
1278 ResTable::normalizeForOutput(pkg.c_str()).c_str());
1279 int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR,
1280 &error);
1281 if (error != "") {
1282 SourcePos(manifestFile, tree.getLineNumber()).error(
1283 "ERROR getting 'android:versionCode' attribute: %s",
1284 error.c_str());
1285 goto bail;
1286 }
1287 if (versionCode > 0) {
1288 printf("versionCode='%d' ", versionCode);
1289 } else {
1290 printf("versionCode='' ");
1291 }
1292 String8 versionName = AaptXml::getResolvedAttribute(res, tree,
1293 VERSION_NAME_ATTR, &error);
1294 if (error != "") {
1295 SourcePos(manifestFile, tree.getLineNumber()).error(
1296 "ERROR getting 'android:versionName' attribute: %s",
1297 error.c_str());
1298 goto bail;
1299 }
1300 printf("versionName='%s'",
1301 ResTable::normalizeForOutput(versionName.c_str()).c_str());
1302
1303 String8 splitName = AaptXml::getAttribute(tree, NULL, "split");
1304 if (!splitName.empty()) {
1305 printf(" split='%s'", ResTable::normalizeForOutput(
1306 splitName.c_str()).c_str());
1307 }
1308
1309 // For 'platformBuildVersionName', using both string and int type as a fallback
1310 // since it may be the code name of Android or the API level.
1311 String8 platformBuildVersionName = AaptXml::getAttribute(tree, NULL,
1312 "platformBuildVersionName");
1313 int32_t platformBuildVersionNameInt =
1314 AaptXml::getIntegerAttribute(tree, NULL, "platformBuildVersionName", 0,
1315 NULL);
1316 if (platformBuildVersionName != "") {
1317 printf(" platformBuildVersionName='%s'", platformBuildVersionName.c_str());
1318 } else if (platformBuildVersionNameInt > 0) {
1319 printf(" platformBuildVersionName='%d'", platformBuildVersionNameInt);
1320 }
1321
1322 // For 'platformBuildVersionCode', using both string and int type as a fallback
1323 // since it may be the code name of Android or the API level.
1324 String8 platformBuildVersionCode = AaptXml::getAttribute(tree, NULL,
1325 "platformBuildVersionCode");
1326 int32_t platformBuildVersionCodeInt =
1327 AaptXml::getIntegerAttribute(tree, NULL, "platformBuildVersionCode", 0,
1328 NULL);
1329 if (platformBuildVersionCode != "") {
1330 printf(" platformBuildVersionCode='%s'", platformBuildVersionCode.c_str());
1331 } else if (platformBuildVersionCodeInt > 0) {
1332 printf(" platformBuildVersionCode='%d'", platformBuildVersionCodeInt);
1333 }
1334
1335 int32_t compileSdkVersion = AaptXml::getIntegerAttribute(tree,
1336 COMPILE_SDK_VERSION_ATTR, &error);
1337 if (error != "") {
1338 SourcePos(manifestFile, tree.getLineNumber()).error(
1339 "ERROR getting 'android:compileSdkVersion' attribute: %s",
1340 error.c_str());
1341 goto bail;
1342 }
1343 if (compileSdkVersion > 0) {
1344 printf(" compileSdkVersion='%d'", compileSdkVersion);
1345 }
1346
1347 String8 compileSdkVersionCodename = AaptXml::getResolvedAttribute(res, tree,
1348 COMPILE_SDK_VERSION_CODENAME_ATTR, &error);
1349 if (compileSdkVersionCodename != "") {
1350 printf(" compileSdkVersionCodename='%s'", ResTable::normalizeForOutput(
1351 compileSdkVersionCodename.c_str()).c_str());
1352 }
1353
1354 printf("\n");
1355
1356 int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree,
1357 INSTALL_LOCATION_ATTR, &error);
1358 if (error != "") {
1359 SourcePos(manifestFile, tree.getLineNumber()).error(
1360 "ERROR getting 'android:installLocation' attribute: %s",
1361 error.c_str());
1362 goto bail;
1363 }
1364
1365 if (installLocation >= 0) {
1366 printf("install-location:'");
1367 switch (installLocation) {
1368 case 0:
1369 printf("auto");
1370 break;
1371 case 1:
1372 printf("internalOnly");
1373 break;
1374 case 2:
1375 printf("preferExternal");
1376 break;
1377 default:
1378 fprintf(stderr, "Invalid installLocation %d\n", installLocation);
1379 goto bail;
1380 }
1381 printf("'\n");
1382 }
1383 } else if (depth == 2) {
1384 withinApplication = false;
1385 if (tag == "application") {
1386 withinApplication = true;
1387
1388 String8 label;
1389 const size_t NL = locales.size();
1390 for (size_t i=0; i<NL; i++) {
1391 const char* localeStr = locales[i].c_str();
1392 assets.setConfiguration(config, localeStr != NULL ? localeStr : "");
1393 String8 llabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
1394 &error);
1395 if (llabel != "") {
1396 if (localeStr == NULL || strlen(localeStr) == 0) {
1397 label = llabel;
1398 printf("application-label:'%s'\n",
1399 ResTable::normalizeForOutput(llabel.c_str()).c_str());
1400 } else {
1401 if (label == "") {
1402 label = llabel;
1403 }
1404 printf("application-label-%s:'%s'\n", localeStr,
1405 ResTable::normalizeForOutput(llabel.c_str()).c_str());
1406 }
1407 }
1408 }
1409
1410 ResTable_config tmpConfig = config;
1411 const size_t ND = densities.size();
1412 for (size_t i=0; i<ND; i++) {
1413 tmpConfig.density = densities[i];
1414 assets.setConfiguration(tmpConfig);
1415 String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR,
1416 &error);
1417 if (icon != "") {
1418 printf("application-icon-%d:'%s'\n", densities[i],
1419 ResTable::normalizeForOutput(icon.c_str()).c_str());
1420 }
1421 }
1422 assets.setConfiguration(config);
1423
1424 String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR, &error);
1425 if (error != "") {
1426 SourcePos(manifestFile, tree.getLineNumber()).error(
1427 "ERROR getting 'android:icon' attribute: %s", error.c_str());
1428 goto bail;
1429 }
1430 int32_t testOnly = AaptXml::getIntegerAttribute(tree, TEST_ONLY_ATTR, 0,
1431 &error);
1432 if (error != "") {
1433 SourcePos(manifestFile, tree.getLineNumber()).error(
1434 "ERROR getting 'android:testOnly' attribute: %s",
1435 error.c_str());
1436 goto bail;
1437 }
1438
1439 String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
1440 &error);
1441 if (error != "") {
1442 SourcePos(manifestFile, tree.getLineNumber()).error(
1443 "ERROR getting 'android:banner' attribute: %s", error.c_str());
1444 goto bail;
1445 }
1446 printf("application: label='%s' ",
1447 ResTable::normalizeForOutput(label.c_str()).c_str());
1448 printf("icon='%s'", ResTable::normalizeForOutput(icon.c_str()).c_str());
1449 if (banner != "") {
1450 printf(" banner='%s'",
1451 ResTable::normalizeForOutput(banner.c_str()).c_str());
1452 }
1453 printf("\n");
1454 if (testOnly != 0) {
1455 printf("testOnly='%d'\n", testOnly);
1456 }
1457
1458 int32_t isGame = AaptXml::getResolvedIntegerAttribute(res, tree,
1459 ISGAME_ATTR, 0, &error);
1460 if (error != "") {
1461 SourcePos(manifestFile, tree.getLineNumber()).error(
1462 "ERROR getting 'android:isGame' attribute: %s", error.c_str());
1463 goto bail;
1464 }
1465 if (isGame != 0) {
1466 printf("application-isGame\n");
1467 }
1468
1469 int32_t debuggable = AaptXml::getResolvedIntegerAttribute(res, tree,
1470 DEBUGGABLE_ATTR, 0, &error);
1471 if (error != "") {
1472 SourcePos(manifestFile, tree.getLineNumber()).error(
1473 "ERROR getting 'android:debuggable' attribute: %s",
1474 error.c_str());
1475 goto bail;
1476 }
1477 if (debuggable != 0) {
1478 printf("application-debuggable\n");
1479 }
1480
1481 // We must search by name because the multiArch flag hasn't been API
1482 // frozen yet.
1483 int32_t multiArchIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
1484 "multiArch");
1485 if (multiArchIndex >= 0) {
1486 Res_value value;
1487 if (tree.getAttributeValue(multiArchIndex, &value) != NO_ERROR) {
1488 if (value.dataType >= Res_value::TYPE_FIRST_INT &&
1489 value.dataType <= Res_value::TYPE_LAST_INT) {
1490 hasMultiArch = value.data;
1491 }
1492 }
1493 }
1494 } else if (tag == "uses-sdk") {
1495 int32_t code = AaptXml::getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR,
1496 &error);
1497 if (error != "") {
1498 error = "";
1499 String8 name = AaptXml::getResolvedAttribute(res, tree,
1500 MIN_SDK_VERSION_ATTR, &error);
1501 if (error != "") {
1502 SourcePos(manifestFile, tree.getLineNumber()).error(
1503 "ERROR getting 'android:minSdkVersion' attribute: %s",
1504 error.c_str());
1505 goto bail;
1506 }
1507 if (name == "Donut") targetSdk = SDK_DONUT;
1508 printf("sdkVersion:'%s'\n",
1509 ResTable::normalizeForOutput(name.c_str()).c_str());
1510 } else if (code != -1) {
1511 targetSdk = code;
1512 printf("sdkVersion:'%d'\n", code);
1513 }
1514 code = AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR);
1515 if (code != -1) {
1516 printf("maxSdkVersion:'%d'\n", code);
1517 }
1518 code = AaptXml::getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
1519 if (error != "") {
1520 error = "";
1521 String8 name = AaptXml::getResolvedAttribute(res, tree,
1522 TARGET_SDK_VERSION_ATTR, &error);
1523 if (error != "") {
1524 SourcePos(manifestFile, tree.getLineNumber()).error(
1525 "ERROR getting 'android:targetSdkVersion' attribute: %s",
1526 error.c_str());
1527 goto bail;
1528 }
1529 if (name == "Donut" && targetSdk < SDK_DONUT) {
1530 targetSdk = SDK_DONUT;
1531 } else if (name != "" && targetSdk == 0) {
1532 // Bump to current development version
1533 targetSdk = SDK_CUR_DEVELOPMENT;
1534 }
1535 printf("targetSdkVersion:'%s'\n",
1536 ResTable::normalizeForOutput(name.c_str()).c_str());
1537 } else if (code != -1) {
1538 if (targetSdk < code) {
1539 targetSdk = code;
1540 }
1541 printf("targetSdkVersion:'%d'\n", code);
1542 }
1543 } else if (tag == "uses-configuration") {
1544 int32_t reqTouchScreen = AaptXml::getIntegerAttribute(tree,
1545 REQ_TOUCH_SCREEN_ATTR, 0);
1546 int32_t reqKeyboardType = AaptXml::getIntegerAttribute(tree,
1547 REQ_KEYBOARD_TYPE_ATTR, 0);
1548 int32_t reqHardKeyboard = AaptXml::getIntegerAttribute(tree,
1549 REQ_HARD_KEYBOARD_ATTR, 0);
1550 int32_t reqNavigation = AaptXml::getIntegerAttribute(tree,
1551 REQ_NAVIGATION_ATTR, 0);
1552 int32_t reqFiveWayNav = AaptXml::getIntegerAttribute(tree,
1553 REQ_FIVE_WAY_NAV_ATTR, 0);
1554 printf("uses-configuration:");
1555 if (reqTouchScreen != 0) {
1556 printf(" reqTouchScreen='%d'", reqTouchScreen);
1557 }
1558 if (reqKeyboardType != 0) {
1559 printf(" reqKeyboardType='%d'", reqKeyboardType);
1560 }
1561 if (reqHardKeyboard != 0) {
1562 printf(" reqHardKeyboard='%d'", reqHardKeyboard);
1563 }
1564 if (reqNavigation != 0) {
1565 printf(" reqNavigation='%d'", reqNavigation);
1566 }
1567 if (reqFiveWayNav != 0) {
1568 printf(" reqFiveWayNav='%d'", reqFiveWayNav);
1569 }
1570 printf("\n");
1571 } else if (tag == "supports-input") {
1572 withinSupportsInput = true;
1573 } else if (tag == "supports-screens") {
1574 smallScreen = AaptXml::getIntegerAttribute(tree,
1575 SMALL_SCREEN_ATTR, 1);
1576 normalScreen = AaptXml::getIntegerAttribute(tree,
1577 NORMAL_SCREEN_ATTR, 1);
1578 largeScreen = AaptXml::getIntegerAttribute(tree,
1579 LARGE_SCREEN_ATTR, 1);
1580 xlargeScreen = AaptXml::getIntegerAttribute(tree,
1581 XLARGE_SCREEN_ATTR, 1);
1582 anyDensity = AaptXml::getIntegerAttribute(tree,
1583 ANY_DENSITY_ATTR, 1);
1584 requiresSmallestWidthDp = AaptXml::getIntegerAttribute(tree,
1585 REQUIRES_SMALLEST_WIDTH_DP_ATTR, 0);
1586 compatibleWidthLimitDp = AaptXml::getIntegerAttribute(tree,
1587 COMPATIBLE_WIDTH_LIMIT_DP_ATTR, 0);
1588 largestWidthLimitDp = AaptXml::getIntegerAttribute(tree,
1589 LARGEST_WIDTH_LIMIT_DP_ATTR, 0);
1590 } else if (tag == "feature-group") {
1591 withinFeatureGroup = true;
1592 FeatureGroup group;
1593 group.label = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR, &error);
1594 if (error != "") {
1595 SourcePos(manifestFile, tree.getLineNumber()).error(
1596 "ERROR getting 'android:label' attribute: %s", error.c_str());
1597 goto bail;
1598 }
1599 featureGroups.add(group);
1600
1601 } else if (tag == "uses-feature") {
1602 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1603 if (name != "" && error == "") {
1604 const char* androidSchema =
1605 "http://schemas.android.com/apk/res/android";
1606
1607 int32_t req = AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1,
1608 &error);
1609 if (error != "") {
1610 SourcePos(manifestFile, tree.getLineNumber()).error(
1611 "failed to read attribute 'android:required': %s",
1612 error.c_str());
1613 goto bail;
1614 }
1615
1616 int32_t version = AaptXml::getIntegerAttribute(tree, androidSchema,
1617 "version", 0, &error);
1618 if (error != "") {
1619 SourcePos(manifestFile, tree.getLineNumber()).error(
1620 "failed to read attribute 'android:version': %s",
1621 error.c_str());
1622 goto bail;
1623 }
1624
1625 commonFeatures.features.add(name, Feature(req != 0, version));
1626 if (req) {
1627 addParentFeatures(&commonFeatures, name);
1628 }
1629 } else {
1630 int vers = AaptXml::getIntegerAttribute(tree,
1631 GL_ES_VERSION_ATTR, &error);
1632 if (error == "") {
1633 if (vers > commonFeatures.openGLESVersion) {
1634 commonFeatures.openGLESVersion = vers;
1635 }
1636 }
1637 }
1638 } else if (tag == "uses-permission") {
1639 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1640 if (error != "") {
1641 SourcePos(manifestFile, tree.getLineNumber()).error(
1642 "ERROR getting 'android:name' attribute: %s", error.c_str());
1643 goto bail;
1644 }
1645
1646 if (name == "") {
1647 SourcePos(manifestFile, tree.getLineNumber()).error(
1648 "ERROR: missing 'android:name' for uses-permission");
1649 goto bail;
1650 }
1651
1652 addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, false);
1653
1654 const int32_t maxSdkVersion =
1655 AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, -1);
1656 const String8 requiredFeature = AaptXml::getAttribute(tree,
1657 REQUIRED_FEATURE_ATTR, &error);
1658 const String8 requiredNotFeature = AaptXml::getAttribute(tree,
1659 REQUIRED_NOT_FEATURE_ATTR, &error);
1660
1661 if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
1662 hasWriteExternalStoragePermission = true;
1663 writeExternalStoragePermissionMaxSdkVersion = maxSdkVersion;
1664 } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
1665 hasReadExternalStoragePermission = true;
1666 } else if (name == "android.permission.READ_PHONE_STATE") {
1667 hasReadPhoneStatePermission = true;
1668 } else if (name == "android.permission.READ_CONTACTS") {
1669 hasReadContactsPermission = true;
1670 } else if (name == "android.permission.WRITE_CONTACTS") {
1671 hasWriteContactsPermission = true;
1672 } else if (name == "android.permission.READ_CALL_LOG") {
1673 hasReadCallLogPermission = true;
1674 } else if (name == "android.permission.WRITE_CALL_LOG") {
1675 hasWriteCallLogPermission = true;
1676 }
1677
1678 printUsesPermission(name,
1679 AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
1680 maxSdkVersion, requiredFeature, requiredNotFeature);
1681
1682 } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
1683 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1684 if (error != "") {
1685 SourcePos(manifestFile, tree.getLineNumber()).error(
1686 "ERROR getting 'android:name' attribute: %s", error.c_str());
1687 goto bail;
1688 }
1689
1690 if (name == "") {
1691 SourcePos(manifestFile, tree.getLineNumber()).error(
1692 "ERROR: missing 'android:name' for uses-permission-sdk-23");
1693 goto bail;
1694 }
1695
1696 addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, true);
1697
1698 printUsesPermissionSdk23(
1699 name, AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
1700
1701 } else if (tag == "uses-package") {
1702 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1703 if (name != "" && error == "") {
1704 printf("uses-package:'%s'\n",
1705 ResTable::normalizeForOutput(name.c_str()).c_str());
1706 } else {
1707 SourcePos(manifestFile, tree.getLineNumber()).error(
1708 "ERROR getting 'android:name' attribute: %s", error.c_str());
1709 goto bail;
1710 }
1711 } else if (tag == "original-package") {
1712 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1713 if (name != "" && error == "") {
1714 printf("original-package:'%s'\n",
1715 ResTable::normalizeForOutput(name.c_str()).c_str());
1716 } else {
1717 SourcePos(manifestFile, tree.getLineNumber()).error(
1718 "ERROR getting 'android:name' attribute: %s", error.c_str());
1719 goto bail;
1720 }
1721 } else if (tag == "supports-gl-texture") {
1722 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1723 if (name != "" && error == "") {
1724 printf("supports-gl-texture:'%s'\n",
1725 ResTable::normalizeForOutput(name.c_str()).c_str());
1726 } else {
1727 SourcePos(manifestFile, tree.getLineNumber()).error(
1728 "ERROR getting 'android:name' attribute: %s", error.c_str());
1729 goto bail;
1730 }
1731 } else if (tag == "compatible-screens") {
1732 printCompatibleScreens(tree, &error);
1733 if (error != "") {
1734 SourcePos(manifestFile, tree.getLineNumber()).error(
1735 "ERROR getting compatible screens: %s", error.c_str());
1736 goto bail;
1737 }
1738 depth--;
1739 } else if (tag == "package-verifier") {
1740 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1741 if (name != "" && error == "") {
1742 String8 publicKey = AaptXml::getAttribute(tree, PUBLIC_KEY_ATTR,
1743 &error);
1744 if (publicKey != "" && error == "") {
1745 printf("package-verifier: name='%s' publicKey='%s'\n",
1746 ResTable::normalizeForOutput(name.c_str()).c_str(),
1747 ResTable::normalizeForOutput(publicKey.c_str()).c_str());
1748 }
1749 }
1750 }
1751 } else if (depth == 3) {
1752 withinActivity = false;
1753 withinReceiver = false;
1754 withinService = false;
1755 withinProvider = false;
1756 hasIntentFilter = false;
1757 hasMetaHostPaymentCategory = false;
1758 hasMetaOffHostPaymentCategory = false;
1759 hasBindDeviceAdminPermission = false;
1760 hasBindAccessibilityServicePermission = false;
1761 hasBindPrintServicePermission = false;
1762 hasBindNfcServicePermission = false;
1763 hasRequiredSafAttributes = false;
1764 hasBindNotificationListenerServicePermission = false;
1765 hasBindDreamServicePermission = false;
1766 if (withinApplication) {
1767 if(tag == "activity") {
1768 withinActivity = true;
1769 activityName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1770 if (error != "") {
1771 SourcePos(manifestFile, tree.getLineNumber()).error(
1772 "ERROR getting 'android:name' attribute: %s",
1773 error.c_str());
1774 goto bail;
1775 }
1776
1777 activityLabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
1778 &error);
1779 if (error != "") {
1780 SourcePos(manifestFile, tree.getLineNumber()).error(
1781 "ERROR getting 'android:label' attribute: %s",
1782 error.c_str());
1783 goto bail;
1784 }
1785
1786 activityIcon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR,
1787 &error);
1788 if (error != "") {
1789 SourcePos(manifestFile, tree.getLineNumber()).error(
1790 "ERROR getting 'android:icon' attribute: %s",
1791 error.c_str());
1792 goto bail;
1793 }
1794
1795 activityBanner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
1796 &error);
1797 if (error != "") {
1798 SourcePos(manifestFile, tree.getLineNumber()).error(
1799 "ERROR getting 'android:banner' attribute: %s",
1800 error.c_str());
1801 goto bail;
1802 }
1803
1804 int32_t orien = AaptXml::getResolvedIntegerAttribute(res, tree,
1805 SCREEN_ORIENTATION_ATTR, &error);
1806 if (error == "") {
1807 if (orien == 0 || orien == 6 || orien == 8) {
1808 // Requests landscape, sensorLandscape, or reverseLandscape.
1809 addImpliedFeature(
1810 &impliedFeatures, "android.hardware.screen.landscape",
1811 String8("one or more activities have specified a "
1812 "landscape orientation"),
1813 false);
1814 } else if (orien == 1 || orien == 7 || orien == 9) {
1815 // Requests portrait, sensorPortrait, or reversePortrait.
1816 addImpliedFeature(
1817 &impliedFeatures, "android.hardware.screen.portrait",
1818 String8("one or more activities have specified a "
1819 "portrait orientation"),
1820 false);
1821 }
1822 }
1823 } else if (tag == "uses-library") {
1824 String8 libraryName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1825 if (error != "") {
1826 SourcePos(manifestFile, tree.getLineNumber()).error(
1827 "ERROR getting 'android:name' attribute for uses-library"
1828 " %s", error.c_str());
1829 goto bail;
1830 }
1831 int req = AaptXml::getIntegerAttribute(tree,
1832 REQUIRED_ATTR, 1);
1833 printf("uses-library%s:'%s'\n",
1834 req ? "" : "-not-required", ResTable::normalizeForOutput(
1835 libraryName.c_str()).c_str());
1836 } else if (tag == "receiver") {
1837 withinReceiver = true;
1838 receiverName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1839
1840 if (error != "") {
1841 SourcePos(manifestFile, tree.getLineNumber()).error(
1842 "ERROR getting 'android:name' attribute for receiver:"
1843 " %s", error.c_str());
1844 goto bail;
1845 }
1846
1847 String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR,
1848 &error);
1849 if (error == "") {
1850 if (permission == "android.permission.BIND_DEVICE_ADMIN") {
1851 hasBindDeviceAdminPermission = true;
1852 }
1853 } else {
1854 SourcePos(manifestFile, tree.getLineNumber()).error(
1855 "ERROR getting 'android:permission' attribute for"
1856 " receiver '%s': %s",
1857 receiverName.c_str(), error.c_str());
1858 }
1859 } else if (tag == "service") {
1860 withinService = true;
1861 serviceName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1862
1863 if (error != "") {
1864 SourcePos(manifestFile, tree.getLineNumber()).error(
1865 "ERROR getting 'android:name' attribute for "
1866 "service:%s", error.c_str());
1867 goto bail;
1868 }
1869
1870 String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR,
1871 &error);
1872 if (error == "") {
1873 if (permission ==
1874 "android.permission.BIND_ACCESSIBILITY_SERVICE") {
1875 hasBindAccessibilityServicePermission = true;
1876 } else if (permission ==
1877 "android.permission.BIND_PRINT_SERVICE") {
1878 hasBindPrintServicePermission = true;
1879 } else if (permission ==
1880 "android.permission.BIND_NFC_SERVICE") {
1881 hasBindNfcServicePermission = true;
1882 } else if (permission ==
1883 "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
1884 hasBindNotificationListenerServicePermission = true;
1885 } else if (permission == "android.permission.BIND_DREAM_SERVICE") {
1886 hasBindDreamServicePermission = true;
1887 }
1888 } else {
1889 SourcePos(manifestFile, tree.getLineNumber()).error(
1890 "ERROR getting 'android:permission' attribute for "
1891 "service '%s': %s", serviceName.c_str(), error.c_str());
1892 }
1893 } else if (tag == "provider") {
1894 withinProvider = true;
1895
1896 bool exported = AaptXml::getResolvedIntegerAttribute(res, tree,
1897 EXPORTED_ATTR, &error);
1898 if (error != "") {
1899 SourcePos(manifestFile, tree.getLineNumber()).error(
1900 "ERROR getting 'android:exported' attribute for provider:"
1901 " %s", error.c_str());
1902 goto bail;
1903 }
1904
1905 bool grantUriPermissions = AaptXml::getResolvedIntegerAttribute(
1906 res, tree, GRANT_URI_PERMISSIONS_ATTR, &error);
1907 if (error != "") {
1908 SourcePos(manifestFile, tree.getLineNumber()).error(
1909 "ERROR getting 'android:grantUriPermissions' attribute for "
1910 "provider: %s", error.c_str());
1911 goto bail;
1912 }
1913
1914 String8 permission = AaptXml::getResolvedAttribute(res, tree,
1915 PERMISSION_ATTR, &error);
1916 if (error != "") {
1917 SourcePos(manifestFile, tree.getLineNumber()).error(
1918 "ERROR getting 'android:permission' attribute for "
1919 "provider: %s", error.c_str());
1920 goto bail;
1921 }
1922
1923 hasRequiredSafAttributes |= exported && grantUriPermissions &&
1924 permission == "android.permission.MANAGE_DOCUMENTS";
1925
1926 } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
1927 String8 metaDataName = AaptXml::getResolvedAttribute(res, tree,
1928 NAME_ATTR, &error);
1929 if (error != "") {
1930 SourcePos(manifestFile, tree.getLineNumber()).error(
1931 "ERROR getting 'android:name' attribute for "
1932 "meta-data: %s", error.c_str());
1933 goto bail;
1934 }
1935 printf("meta-data: name='%s' ",
1936 ResTable::normalizeForOutput(metaDataName.c_str()).c_str());
1937 printResolvedResourceAttribute(res, tree, VALUE_ATTR, String8("value"),
1938 &error);
1939 if (error != "") {
1940 // Try looking for a RESOURCE_ATTR
1941 error = "";
1942 printResolvedResourceAttribute(res, tree, RESOURCE_ATTR,
1943 String8("resource"), &error);
1944 if (error != "") {
1945 SourcePos(manifestFile, tree.getLineNumber()).error(
1946 "ERROR getting 'android:value' or "
1947 "'android:resource' attribute for "
1948 "meta-data: %s", error.c_str());
1949 goto bail;
1950 }
1951 }
1952 printf("\n");
1953 } else if (withinSupportsInput && tag == "input-type") {
1954 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
1955 if (name != "" && error == "") {
1956 supportedInput.add(name);
1957 } else {
1958 SourcePos(manifestFile, tree.getLineNumber()).error(
1959 "ERROR getting 'android:name' attribute: %s",
1960 error.c_str());
1961 goto bail;
1962 }
1963 }
1964 } else if (withinFeatureGroup && tag == "uses-feature") {
1965 const String8 androidSchema("http://schemas.android.com/apk/res/android");
1966 FeatureGroup& top = featureGroups.editTop();
1967
1968 String8 name = AaptXml::getResolvedAttribute(res, tree, NAME_ATTR, &error);
1969 if (name != "" && error == "") {
1970 Feature feature(true);
1971
1972 int32_t featureVers = AaptXml::getIntegerAttribute(
1973 tree, androidSchema.c_str(), "version", 0, &error);
1974 if (error == "") {
1975 feature.version = featureVers;
1976 } else {
1977 SourcePos(manifestFile, tree.getLineNumber()).error(
1978 "failed to read attribute 'android:version': %s",
1979 error.c_str());
1980 goto bail;
1981 }
1982
1983 top.features.add(name, feature);
1984 addParentFeatures(&top, name);
1985
1986 } else {
1987 int vers = AaptXml::getIntegerAttribute(tree, GL_ES_VERSION_ATTR,
1988 &error);
1989 if (error == "") {
1990 if (vers > top.openGLESVersion) {
1991 top.openGLESVersion = vers;
1992 }
1993 }
1994 }
1995 }
1996 } else if (depth == 4) {
1997 if (tag == "intent-filter") {
1998 hasIntentFilter = true;
1999 withinIntentFilter = true;
2000 actMainActivity = false;
2001 actWidgetReceivers = false;
2002 actImeService = false;
2003 actWallpaperService = false;
2004 actAccessibilityService = false;
2005 actPrintService = false;
2006 actDeviceAdminEnabled = false;
2007 actHostApduService = false;
2008 actOffHostApduService = false;
2009 actDocumentsProvider = false;
2010 actNotificationListenerService = false;
2011 actDreamService = false;
2012 actCamera = false;
2013 actCameraSecure = false;
2014 catLauncher = false;
2015 } else if (withinService && tag == "meta-data") {
2016 String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
2017 if (error != "") {
2018 SourcePos(manifestFile, tree.getLineNumber()).error(
2019 "ERROR getting 'android:name' attribute for "
2020 "meta-data tag in service '%s': %s", serviceName.c_str(),
2021 error.c_str());
2022 goto bail;
2023 }
2024
2025 if (name == "android.nfc.cardemulation.host_apdu_service" ||
2026 name == "android.nfc.cardemulation.off_host_apdu_service") {
2027 bool offHost = true;
2028 if (name == "android.nfc.cardemulation.host_apdu_service") {
2029 offHost = false;
2030 }
2031
2032 String8 xmlPath = AaptXml::getResolvedAttribute(res, tree,
2033 RESOURCE_ATTR, &error);
2034 if (error != "") {
2035 SourcePos(manifestFile, tree.getLineNumber()).error(
2036 "ERROR getting 'android:resource' attribute for "
2037 "meta-data tag in service '%s': %s",
2038 serviceName.c_str(), error.c_str());
2039 goto bail;
2040 }
2041
2042 Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
2043 offHost, &error);
2044 if (error != "") {
2045 SourcePos(manifestFile, tree.getLineNumber()).error(
2046 "ERROR getting AID category for service '%s'",
2047 serviceName.c_str());
2048 goto bail;
2049 }
2050
2051 const size_t catLen = categories.size();
2052 for (size_t i = 0; i < catLen; i++) {
2053 bool paymentCategory = (categories[i] == "payment");
2054 if (offHost) {
2055 hasMetaOffHostPaymentCategory |= paymentCategory;
2056 } else {
2057 hasMetaHostPaymentCategory |= paymentCategory;
2058 }
2059 }
2060 }
2061 }
2062 } else if ((depth == 5) && withinIntentFilter) {
2063 String8 action;
2064 if (tag == "action") {
2065 action = AaptXml::getAttribute(tree, NAME_ATTR, &error);
2066 if (error != "") {
2067 SourcePos(manifestFile, tree.getLineNumber()).error(
2068 "ERROR getting 'android:name' attribute: %s", error.c_str());
2069 goto bail;
2070 }
2071
2072 if (withinActivity) {
2073 if (action == "android.intent.action.MAIN") {
2074 isMainActivity = true;
2075 actMainActivity = true;
2076 } else if (action == "android.media.action.STILL_IMAGE_CAMERA" ||
2077 action == "android.media.action.VIDEO_CAMERA") {
2078 actCamera = true;
2079 } else if (action == "android.media.action.STILL_IMAGE_CAMERA_SECURE") {
2080 actCameraSecure = true;
2081 }
2082 } else if (withinReceiver) {
2083 if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
2084 actWidgetReceivers = true;
2085 } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
2086 actDeviceAdminEnabled = true;
2087 }
2088 } else if (withinService) {
2089 if (action == "android.view.InputMethod") {
2090 actImeService = true;
2091 } else if (action == "android.service.wallpaper.WallpaperService") {
2092 actWallpaperService = true;
2093 } else if (action ==
2094 "android.accessibilityservice.AccessibilityService") {
2095 actAccessibilityService = true;
2096 } else if (action =="android.printservice.PrintService") {
2097 actPrintService = true;
2098 } else if (action ==
2099 "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
2100 actHostApduService = true;
2101 } else if (action ==
2102 "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
2103 actOffHostApduService = true;
2104 } else if (action ==
2105 "android.service.notification.NotificationListenerService") {
2106 actNotificationListenerService = true;
2107 } else if (action == "android.service.dreams.DreamService") {
2108 actDreamService = true;
2109 }
2110 } else if (withinProvider) {
2111 if (action == "android.content.action.DOCUMENTS_PROVIDER") {
2112 actDocumentsProvider = true;
2113 }
2114 }
2115 if (action == "android.intent.action.SEARCH") {
2116 isSearchable = true;
2117 }
2118 }
2119
2120 if (tag == "category") {
2121 String8 category = AaptXml::getAttribute(tree, NAME_ATTR, &error);
2122 if (error != "") {
2123 SourcePos(manifestFile, tree.getLineNumber()).error(
2124 "ERROR getting 'name' attribute: %s", error.c_str());
2125 goto bail;
2126 }
2127 if (withinActivity) {
2128 if (category == "android.intent.category.LAUNCHER") {
2129 isLauncherActivity = true;
2130 } else if (category == "android.intent.category.LEANBACK_LAUNCHER") {
2131 isLeanbackLauncherActivity = true;
2132 } else if (category == "android.intent.category.HOME") {
2133 catLauncher = true;
2134 }
2135 }
2136 }
2137 }
2138 }
2139
2140 // Pre-1.6 implicitly granted permission compatibility logic
2141 if (targetSdk < SDK_DONUT) {
2142 if (!hasWriteExternalStoragePermission) {
2143 printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
2144 printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
2145 String8("targetSdkVersion < 4"));
2146 hasWriteExternalStoragePermission = true;
2147 }
2148 if (!hasReadPhoneStatePermission) {
2149 printUsesPermission(String8("android.permission.READ_PHONE_STATE"));
2150 printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"),
2151 String8("targetSdkVersion < 4"));
2152 }
2153 }
2154
2155 // If the application has requested WRITE_EXTERNAL_STORAGE, we will
2156 // force them to always take READ_EXTERNAL_STORAGE as well. We always
2157 // do this (regardless of target API version) because we can't have
2158 // an app with write permission but not read permission.
2159 if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
2160 printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
2161 false /* optional */, writeExternalStoragePermissionMaxSdkVersion);
2162 printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
2163 String8("requested WRITE_EXTERNAL_STORAGE"),
2164 writeExternalStoragePermissionMaxSdkVersion);
2165 }
2166
2167 // Pre-JellyBean call log permission compatibility.
2168 if (targetSdk < SDK_JELLY_BEAN) {
2169 if (!hasReadCallLogPermission && hasReadContactsPermission) {
2170 printUsesPermission(String8("android.permission.READ_CALL_LOG"));
2171 printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
2172 String8("targetSdkVersion < 16 and requested READ_CONTACTS"));
2173 }
2174 if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
2175 printUsesPermission(String8("android.permission.WRITE_CALL_LOG"));
2176 printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"),
2177 String8("targetSdkVersion < 16 and requested WRITE_CONTACTS"));
2178 }
2179 }
2180
2181 // If the app hasn't declared the touchscreen as a feature requirement (either
2182 // directly or implied, required or not), then the faketouch feature is implied.
2183 if (!hasFeature("android.hardware.touchscreen", commonFeatures, impliedFeatures)) {
2184 addImpliedFeature(&impliedFeatures, "android.hardware.faketouch",
2185 String8("default feature for all apps"), false);
2186 }
2187
2188 const size_t numFeatureGroups = featureGroups.size();
2189 if (numFeatureGroups == 0) {
2190 // If no <feature-group> tags were defined, apply auto-implied features.
2191 printDefaultFeatureGroup(commonFeatures, impliedFeatures);
2192
2193 } else {
2194 // <feature-group> tags are defined, so we ignore implied features and
2195 for (size_t i = 0; i < numFeatureGroups; i++) {
2196 FeatureGroup& grp = featureGroups.editItemAt(i);
2197
2198 if (commonFeatures.openGLESVersion > grp.openGLESVersion) {
2199 grp.openGLESVersion = commonFeatures.openGLESVersion;
2200 }
2201
2202 // Merge the features defined in the top level (not inside a <feature-group>)
2203 // with this feature group.
2204 const size_t numCommonFeatures = commonFeatures.features.size();
2205 for (size_t j = 0; j < numCommonFeatures; j++) {
2206 if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) {
2207 grp.features.add(commonFeatures.features.keyAt(j),
2208 commonFeatures.features[j]);
2209 }
2210 }
2211
2212 if (!grp.features.isEmpty()) {
2213 printFeatureGroup(grp);
2214 }
2215 }
2216 }
2217
2218
2219 if (hasWidgetReceivers) {
2220 printComponentPresence("app-widget");
2221 }
2222 if (hasDeviceAdminReceiver) {
2223 printComponentPresence("device-admin");
2224 }
2225 if (hasImeService) {
2226 printComponentPresence("ime");
2227 }
2228 if (hasWallpaperService) {
2229 printComponentPresence("wallpaper");
2230 }
2231 if (hasAccessibilityService) {
2232 printComponentPresence("accessibility");
2233 }
2234 if (hasPrintService) {
2235 printComponentPresence("print-service");
2236 }
2237 if (hasPaymentService) {
2238 printComponentPresence("payment");
2239 }
2240 if (isSearchable) {
2241 printComponentPresence("search");
2242 }
2243 if (hasDocumentsProvider) {
2244 printComponentPresence("document-provider");
2245 }
2246 if (hasLauncher) {
2247 printComponentPresence("launcher");
2248 }
2249 if (hasNotificationListenerService) {
2250 printComponentPresence("notification-listener");
2251 }
2252 if (hasDreamService) {
2253 printComponentPresence("dream");
2254 }
2255 if (hasCameraActivity) {
2256 printComponentPresence("camera");
2257 }
2258 if (hasCameraSecureActivity) {
2259 printComponentPresence("camera-secure");
2260 }
2261
2262 if (hasMainActivity) {
2263 printf("main\n");
2264 }
2265 if (hasOtherActivities) {
2266 printf("other-activities\n");
2267 }
2268 if (hasOtherReceivers) {
2269 printf("other-receivers\n");
2270 }
2271 if (hasOtherServices) {
2272 printf("other-services\n");
2273 }
2274
2275 // For modern apps, if screen size buckets haven't been specified
2276 // but the new width ranges have, then infer the buckets from them.
2277 if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
2278 && requiresSmallestWidthDp > 0) {
2279 int compatWidth = compatibleWidthLimitDp;
2280 if (compatWidth <= 0) {
2281 compatWidth = requiresSmallestWidthDp;
2282 }
2283 if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
2284 smallScreen = -1;
2285 } else {
2286 smallScreen = 0;
2287 }
2288 if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
2289 normalScreen = -1;
2290 } else {
2291 normalScreen = 0;
2292 }
2293 if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
2294 largeScreen = -1;
2295 } else {
2296 largeScreen = 0;
2297 }
2298 if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
2299 xlargeScreen = -1;
2300 } else {
2301 xlargeScreen = 0;
2302 }
2303 }
2304
2305 // Determine default values for any unspecified screen sizes,
2306 // based on the target SDK of the package. As of 4 (donut)
2307 // the screen size support was introduced, so all default to
2308 // enabled.
2309 if (smallScreen > 0) {
2310 smallScreen = targetSdk >= SDK_DONUT ? -1 : 0;
2311 }
2312 if (normalScreen > 0) {
2313 normalScreen = -1;
2314 }
2315 if (largeScreen > 0) {
2316 largeScreen = targetSdk >= SDK_DONUT ? -1 : 0;
2317 }
2318 if (xlargeScreen > 0) {
2319 // Introduced in Gingerbread.
2320 xlargeScreen = targetSdk >= SDK_GINGERBREAD ? -1 : 0;
2321 }
2322 if (anyDensity > 0) {
2323 anyDensity = (targetSdk >= SDK_DONUT || requiresSmallestWidthDp > 0 ||
2324 compatibleWidthLimitDp > 0)
2325 ? -1
2326 : 0;
2327 }
2328 printf("supports-screens:");
2329 if (smallScreen != 0) {
2330 printf(" 'small'");
2331 }
2332 if (normalScreen != 0) {
2333 printf(" 'normal'");
2334 }
2335 if (largeScreen != 0) {
2336 printf(" 'large'");
2337 }
2338 if (xlargeScreen != 0) {
2339 printf(" 'xlarge'");
2340 }
2341 printf("\n");
2342 printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
2343 if (requiresSmallestWidthDp > 0) {
2344 printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
2345 }
2346 if (compatibleWidthLimitDp > 0) {
2347 printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
2348 }
2349 if (largestWidthLimitDp > 0) {
2350 printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
2351 }
2352
2353 printf("locales:");
2354 const size_t NL = locales.size();
2355 for (size_t i=0; i<NL; i++) {
2356 const char* localeStr = locales[i].c_str();
2357 if (localeStr == NULL || strlen(localeStr) == 0) {
2358 localeStr = "--_--";
2359 }
2360 printf(" '%s'", localeStr);
2361 }
2362 printf("\n");
2363
2364 printf("densities:");
2365 const size_t ND = densities.size();
2366 for (size_t i=0; i<ND; i++) {
2367 printf(" '%d'", densities[i]);
2368 }
2369 printf("\n");
2370
2371 AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
2372 if (dir != NULL) {
2373 if (dir->getFileCount() > 0) {
2374 SortedVector<String8> architectures;
2375 for (size_t i=0; i<dir->getFileCount(); i++) {
2376 architectures.add(ResTable::normalizeForOutput(
2377 dir->getFileName(i).c_str()));
2378 }
2379
2380 bool outputAltNativeCode = false;
2381 // A multiArch package is one that contains 64-bit and
2382 // 32-bit versions of native code and expects 3rd-party
2383 // apps to load these native code libraries. Since most
2384 // 64-bit systems also support 32-bit apps, the apps
2385 // loading this multiArch package's code may be either
2386 // 32-bit or 64-bit.
2387 if (hasMultiArch) {
2388 // If this is a multiArch package, report the 64-bit
2389 // version only. Then as a separate entry, report the
2390 // rest.
2391 //
2392 // If we report the 32-bit architecture, this APK will
2393 // be installed on a 32-bit device, causing a large waste
2394 // of bandwidth and disk space. This assumes that
2395 // the developer of the multiArch package has also
2396 // made a version that is 32-bit only.
2397 String8 intel64("x86_64");
2398 String8 arm64("arm64-v8a");
2399 ssize_t index = architectures.indexOf(intel64);
2400 if (index < 0) {
2401 index = architectures.indexOf(arm64);
2402 }
2403
2404 if (index >= 0) {
2405 printf("native-code: '%s'\n", architectures[index].c_str());
2406 architectures.removeAt(index);
2407 outputAltNativeCode = true;
2408 }
2409 }
2410
2411 const size_t archCount = architectures.size();
2412 if (archCount > 0) {
2413 if (outputAltNativeCode) {
2414 printf("alt-");
2415 }
2416 printf("native-code:");
2417 for (size_t i = 0; i < archCount; i++) {
2418 printf(" '%s'", architectures[i].c_str());
2419 }
2420 printf("\n");
2421 }
2422 }
2423 delete dir;
2424 }
2425 } else if (strcmp("badger", option) == 0) {
2426 printf("%s", CONSOLE_DATA);
2427 } else if (strcmp("configurations", option) == 0) {
2428 Vector<ResTable_config> configs;
2429 res.getConfigurations(&configs);
2430 const size_t N = configs.size();
2431 for (size_t i=0; i<N; i++) {
2432 printf("%s\n", configs[i].toString().c_str());
2433 }
2434 } else {
2435 fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
2436 goto bail;
2437 }
2438 }
2439
2440 result = NO_ERROR;
2441
2442 bail:
2443 if (SourcePos::hasErrors()) {
2444 SourcePos::printErrors(stderr);
2445 }
2446
2447 if (asset) {
2448 delete asset;
2449 }
2450 return (result != NO_ERROR);
2451 }
2452
2453
2454 /*
2455 * Handle the "add" command, which wants to add files to a new or
2456 * pre-existing archive.
2457 */
doAdd(Bundle * bundle)2458 int doAdd(Bundle* bundle)
2459 {
2460 ZipFile* zip = NULL;
2461 status_t result = UNKNOWN_ERROR;
2462 const char* zipFileName;
2463
2464 if (bundle->getUpdate()) {
2465 /* avoid confusion */
2466 fprintf(stderr, "ERROR: can't use '-u' with add\n");
2467 goto bail;
2468 }
2469
2470 if (bundle->getFileSpecCount() < 1) {
2471 fprintf(stderr, "ERROR: must specify zip file name\n");
2472 goto bail;
2473 }
2474 zipFileName = bundle->getFileSpecEntry(0);
2475
2476 if (bundle->getFileSpecCount() < 2) {
2477 fprintf(stderr, "NOTE: nothing to do\n");
2478 goto bail;
2479 }
2480
2481 zip = openReadWrite(zipFileName, true);
2482 if (zip == NULL) {
2483 fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
2484 goto bail;
2485 }
2486
2487 for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2488 const char* fileName = bundle->getFileSpecEntry(i);
2489
2490 if (strcasecmp(getPathExtension(String8(fileName)).c_str(), ".gz") == 0) {
2491 printf(" '%s'... (from gzip)\n", fileName);
2492 result = zip->addGzip(fileName, getBasePath(String8(fileName)).c_str(), NULL);
2493 } else {
2494 if (bundle->getJunkPath()) {
2495 String8 storageName = getPathLeaf(String8(fileName));
2496 printf(" '%s' as '%s'...\n", fileName,
2497 ResTable::normalizeForOutput(storageName.c_str()).c_str());
2498 result = zip->add(fileName, storageName.c_str(),
2499 bundle->getCompressionMethod(), NULL);
2500 } else {
2501 printf(" '%s'...\n", fileName);
2502 result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
2503 }
2504 }
2505 if (result != NO_ERROR) {
2506 fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
2507 if (result == NAME_NOT_FOUND) {
2508 fprintf(stderr, ": file not found\n");
2509 } else if (result == ALREADY_EXISTS) {
2510 fprintf(stderr, ": already exists in archive\n");
2511 } else {
2512 fprintf(stderr, "\n");
2513 }
2514 goto bail;
2515 }
2516 }
2517
2518 result = NO_ERROR;
2519
2520 bail:
2521 delete zip;
2522 return (result != NO_ERROR);
2523 }
2524
2525
2526 /*
2527 * Delete files from an existing archive.
2528 */
doRemove(Bundle * bundle)2529 int doRemove(Bundle* bundle)
2530 {
2531 ZipFile* zip = NULL;
2532 status_t result = UNKNOWN_ERROR;
2533 const char* zipFileName;
2534
2535 if (bundle->getFileSpecCount() < 1) {
2536 fprintf(stderr, "ERROR: must specify zip file name\n");
2537 goto bail;
2538 }
2539 zipFileName = bundle->getFileSpecEntry(0);
2540
2541 if (bundle->getFileSpecCount() < 2) {
2542 fprintf(stderr, "NOTE: nothing to do\n");
2543 goto bail;
2544 }
2545
2546 zip = openReadWrite(zipFileName, false);
2547 if (zip == NULL) {
2548 fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
2549 zipFileName);
2550 goto bail;
2551 }
2552
2553 for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2554 const char* fileName = bundle->getFileSpecEntry(i);
2555 ZipEntry* entry;
2556
2557 entry = zip->getEntryByName(fileName);
2558 if (entry == NULL) {
2559 printf(" '%s' NOT FOUND\n", fileName);
2560 continue;
2561 }
2562
2563 result = zip->remove(entry);
2564
2565 if (result != NO_ERROR) {
2566 fprintf(stderr, "Unable to delete '%s' from '%s'\n",
2567 bundle->getFileSpecEntry(i), zipFileName);
2568 goto bail;
2569 }
2570 }
2571
2572 /* update the archive */
2573 zip->flush();
2574
2575 bail:
2576 delete zip;
2577 return (result != NO_ERROR);
2578 }
2579
addResourcesToBuilder(const sp<AaptDir> & dir,const sp<ApkBuilder> & builder,bool ignoreConfig=false)2580 static status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
2581 const size_t numDirs = dir->getDirs().size();
2582 for (size_t i = 0; i < numDirs; i++) {
2583 bool ignore = ignoreConfig;
2584 const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
2585 const char* dirStr = subDir->getLeaf().c_str();
2586 if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
2587 ignore = true;
2588 }
2589 status_t err = addResourcesToBuilder(subDir, builder, ignore);
2590 if (err != NO_ERROR) {
2591 return err;
2592 }
2593 }
2594
2595 const size_t numFiles = dir->getFiles().size();
2596 for (size_t i = 0; i < numFiles; i++) {
2597 sp<AaptGroup> gp = dir->getFiles().valueAt(i);
2598 const size_t numConfigs = gp->getFiles().size();
2599 for (size_t j = 0; j < numConfigs; j++) {
2600 status_t err = NO_ERROR;
2601 if (ignoreConfig) {
2602 err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
2603 } else {
2604 err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
2605 }
2606 if (err != NO_ERROR) {
2607 fprintf(stderr, "Failed to add %s (%s) to builder.\n",
2608 gp->getPath().c_str(), gp->getFiles()[j]->getPrintableSource().c_str());
2609 return err;
2610 }
2611 }
2612 }
2613 return NO_ERROR;
2614 }
2615
buildApkName(const String8 & original,const sp<ApkSplit> & split)2616 static String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
2617 if (split->isBase()) {
2618 return original;
2619 }
2620
2621 String8 ext(getPathExtension(original));
2622 if (ext == String8(".apk")) {
2623 return String8::format("%s_%s%s",
2624 getBasePath(original).c_str(),
2625 split->getDirectorySafeName().c_str(),
2626 ext.c_str());
2627 }
2628
2629 return String8::format("%s_%s", original.c_str(),
2630 split->getDirectorySafeName().c_str());
2631 }
2632
2633 /*
2634 * Package up an asset directory and associated application files.
2635 */
doPackage(Bundle * bundle)2636 int doPackage(Bundle* bundle)
2637 {
2638 const char* outputAPKFile;
2639 int retVal = 1;
2640 status_t err;
2641 sp<AaptAssets> assets;
2642 int N;
2643 FILE* fp;
2644 String8 dependencyFile;
2645 sp<ApkBuilder> builder;
2646
2647 // -c en_XA or/and ar_XB means do pseudolocalization
2648 sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
2649 err = configFilter->parse(bundle->getConfigurations());
2650 if (err != NO_ERROR) {
2651 goto bail;
2652 }
2653 if (configFilter->containsPseudo()) {
2654 bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
2655 }
2656 if (configFilter->containsPseudoBidi()) {
2657 bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
2658 }
2659
2660 N = bundle->getFileSpecCount();
2661 if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
2662 && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
2663 fprintf(stderr, "ERROR: no input files\n");
2664 goto bail;
2665 }
2666
2667 outputAPKFile = bundle->getOutputAPKFile();
2668
2669 // Make sure the filenames provided exist and are of the appropriate type.
2670 if (outputAPKFile) {
2671 FileType type;
2672 type = getFileType(outputAPKFile);
2673 if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
2674 fprintf(stderr,
2675 "ERROR: output file '%s' exists but is not regular file\n",
2676 outputAPKFile);
2677 goto bail;
2678 }
2679 }
2680
2681 // Load the assets.
2682 assets = new AaptAssets();
2683
2684 // Set up the resource gathering in assets if we're going to generate
2685 // dependency files. Every time we encounter a resource while slurping
2686 // the tree, we'll add it to these stores so we have full resource paths
2687 // to write to a dependency file.
2688 if (bundle->getGenDependencies()) {
2689 sp<FilePathStore> resPathStore = new FilePathStore;
2690 assets->setFullResPaths(resPathStore);
2691 sp<FilePathStore> assetPathStore = new FilePathStore;
2692 assets->setFullAssetPaths(assetPathStore);
2693 }
2694
2695 err = assets->slurpFromArgs(bundle);
2696 if (err < 0) {
2697 goto bail;
2698 }
2699
2700 if (bundle->getVerbose()) {
2701 assets->print(String8());
2702 }
2703
2704 // Create the ApkBuilder, which will collect the compiled files
2705 // to write to the final APK (or sets of APKs if we are building
2706 // a Split APK.
2707 builder = new ApkBuilder(configFilter);
2708
2709 // If we are generating a Split APK, find out which configurations to split on.
2710 if (bundle->getSplitConfigurations().size() > 0) {
2711 const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
2712 const size_t numSplits = splitStrs.size();
2713 for (size_t i = 0; i < numSplits; i++) {
2714 std::set<ConfigDescription> configs;
2715 if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
2716 fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].c_str());
2717 goto bail;
2718 }
2719
2720 err = builder->createSplitForConfigs(configs);
2721 if (err != NO_ERROR) {
2722 goto bail;
2723 }
2724 }
2725 }
2726
2727 // If they asked for any fileAs that need to be compiled, do so.
2728 if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
2729 err = buildResources(bundle, assets, builder);
2730 if (err != 0) {
2731 goto bail;
2732 }
2733 }
2734
2735 // At this point we've read everything and processed everything. From here
2736 // on out it's just writing output files.
2737 if (SourcePos::hasErrors()) {
2738 goto bail;
2739 }
2740
2741 // Update symbols with information about which ones are needed as Java symbols.
2742 assets->applyJavaSymbols();
2743 if (SourcePos::hasErrors()) {
2744 goto bail;
2745 }
2746
2747 // If we've been asked to generate a dependency file, do that here
2748 if (bundle->getGenDependencies()) {
2749 // If this is the packaging step, generate the dependency file next to
2750 // the output apk (e.g. bin/resources.ap_.d)
2751 if (outputAPKFile) {
2752 dependencyFile = String8(outputAPKFile);
2753 // Add the .d extension to the dependency file.
2754 dependencyFile.append(".d");
2755 } else {
2756 // Else if this is the R.java dependency generation step,
2757 // generate the dependency file in the R.java package subdirectory
2758 // e.g. gen/com/foo/app/R.java.d
2759 dependencyFile = String8(bundle->getRClassDir());
2760 appendPath(dependencyFile, "R.java.d");
2761 }
2762 // Make sure we have a clean dependency file to start with
2763 fp = fopen(dependencyFile.c_str(), "w");
2764 fclose(fp);
2765 }
2766
2767 // Write out R.java constants
2768 if (!assets->havePrivateSymbols()) {
2769 if (bundle->getCustomPackage() == NULL) {
2770 // Write the R.java file into the appropriate class directory
2771 // e.g. gen/com/foo/app/R.java
2772 err = writeResourceSymbols(bundle, assets, assets->getPackage(), true,
2773 bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2774 } else {
2775 const String8 customPkg(bundle->getCustomPackage());
2776 err = writeResourceSymbols(bundle, assets, customPkg, true,
2777 bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2778 }
2779 if (err < 0) {
2780 goto bail;
2781 }
2782 // If we have library files, we're going to write our R.java file into
2783 // the appropriate class directory for those libraries as well.
2784 // e.g. gen/com/foo/app/lib/R.java
2785 if (bundle->getExtraPackages() != NULL) {
2786 // Split on colon
2787 String8 libs(bundle->getExtraPackages());
2788 char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
2789 while (packageString != NULL) {
2790 // Write the R.java file out with the correct package name
2791 err = writeResourceSymbols(bundle, assets, String8(packageString), true,
2792 bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
2793 if (err < 0) {
2794 goto bail;
2795 }
2796 packageString = strtok(NULL, ":");
2797 }
2798 libs.unlockBuffer();
2799 }
2800 } else {
2801 err = writeResourceSymbols(bundle, assets, assets->getPackage(), false, false);
2802 if (err < 0) {
2803 goto bail;
2804 }
2805 err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true, false);
2806 if (err < 0) {
2807 goto bail;
2808 }
2809 }
2810
2811 // Write out the ProGuard file
2812 err = writeProguardFile(bundle, assets);
2813 if (err < 0) {
2814 goto bail;
2815 }
2816
2817 // Write out the Main Dex ProGuard file
2818 err = writeMainDexProguardFile(bundle, assets);
2819 if (err < 0) {
2820 goto bail;
2821 }
2822
2823 // Write the apk
2824 if (outputAPKFile) {
2825 // Gather all resources and add them to the APK Builder. The builder will then
2826 // figure out which Split they belong in.
2827 err = addResourcesToBuilder(assets, builder);
2828 if (err != NO_ERROR) {
2829 goto bail;
2830 }
2831
2832 const Vector<sp<ApkSplit> >& splits = builder->getSplits();
2833 const size_t numSplits = splits.size();
2834 for (size_t i = 0; i < numSplits; i++) {
2835 const sp<ApkSplit>& split = splits[i];
2836 String8 outputPath = buildApkName(String8(outputAPKFile), split);
2837 err = writeAPK(bundle, outputPath, split);
2838 if (err != NO_ERROR) {
2839 fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.c_str());
2840 goto bail;
2841 }
2842 }
2843 }
2844
2845 // If we've been asked to generate a dependency file, we need to finish up here.
2846 // the writeResourceSymbols and writeAPK functions have already written the target
2847 // half of the dependency file, now we need to write the prerequisites. (files that
2848 // the R.java file or .ap_ file depend on)
2849 if (bundle->getGenDependencies()) {
2850 // Now that writeResourceSymbols or writeAPK has taken care of writing
2851 // the targets to our dependency file, we'll write the prereqs
2852 fp = fopen(dependencyFile.c_str(), "a+");
2853 fprintf(fp, " : ");
2854 bool includeRaw = (outputAPKFile != NULL);
2855 err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
2856 // Also manually add the AndroidManifeset since it's not under res/ or assets/
2857 // and therefore was not added to our pathstores during slurping
2858 fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
2859 fclose(fp);
2860 }
2861
2862 retVal = 0;
2863 bail:
2864 if (SourcePos::hasErrors()) {
2865 SourcePos::printErrors(stderr);
2866 }
2867 return retVal;
2868 }
2869
2870 /*
2871 * Do PNG Crunching
2872 * PRECONDITIONS
2873 * -S flag points to a source directory containing drawable* folders
2874 * -C flag points to destination directory. The folder structure in the
2875 * source directory will be mirrored to the destination (cache) directory
2876 *
2877 * POSTCONDITIONS
2878 * Destination directory will be updated to match the PNG files in
2879 * the source directory.
2880 */
doCrunch(Bundle * bundle)2881 int doCrunch(Bundle* bundle)
2882 {
2883 fprintf(stdout, "Crunching PNG Files in ");
2884 fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
2885 fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
2886
2887 updatePreProcessedCache(bundle);
2888
2889 return NO_ERROR;
2890 }
2891
2892 /*
2893 * Do PNG Crunching on a single flag
2894 * -i points to a single png file
2895 * -o points to a single png output file
2896 */
doSingleCrunch(Bundle * bundle)2897 int doSingleCrunch(Bundle* bundle)
2898 {
2899 fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
2900 fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
2901
2902 String8 input(bundle->getSingleCrunchInputFile());
2903 String8 output(bundle->getSingleCrunchOutputFile());
2904
2905 if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
2906 // we can't return the status_t as it gets truncate to the lower 8 bits.
2907 return 42;
2908 }
2909
2910 return NO_ERROR;
2911 }
2912
runInDaemonMode(Bundle * bundle)2913 int runInDaemonMode(Bundle* bundle) {
2914 std::cout << "Ready" << std::endl;
2915 for (std::string cmd; std::getline(std::cin, cmd);) {
2916 if (cmd == "quit") {
2917 return NO_ERROR;
2918 } else if (cmd == "s") {
2919 // Two argument crunch
2920 std::string inputFile, outputFile;
2921 std::getline(std::cin, inputFile);
2922 std::getline(std::cin, outputFile);
2923 bundle->setSingleCrunchInputFile(inputFile.c_str());
2924 bundle->setSingleCrunchOutputFile(outputFile.c_str());
2925 std::cout << "Crunching " << inputFile << std::endl;
2926 if (doSingleCrunch(bundle) != NO_ERROR) {
2927 std::cout << "Error" << std::endl;
2928 }
2929 std::cout << "Done" << std::endl;
2930 } else {
2931 // in case of invalid command, just bail out.
2932 std::cerr << "Unknown command" << std::endl;
2933 return -1;
2934 }
2935 }
2936 return -1;
2937 }
2938
2939 char CONSOLE_DATA[2925] = {
2940 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2941 32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2942 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2943 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2944 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
2945 86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
2946 62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2947 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2948 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
2949 81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
2950 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2951 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2952 32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
2953 59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2954 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2955 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
2956 59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
2957 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2958 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2959 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
2960 58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
2961 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2962 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2963 47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
2964 121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2965 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2966 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
2967 81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
2968 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2969 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2970 32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
2971 59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2972 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2973 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
2974 59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
2975 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2976 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2977 32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
2978 70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
2979 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2980 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2981 32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
2982 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2983 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2984 32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
2985 81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
2986 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2987 32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
2988 59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
2989 60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2990 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
2991 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
2992 61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
2993 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2994 32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2995 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
2996 109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
2997 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
2998 67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2999 59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
3000 61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
3001 32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
3002 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
3003 73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
3004 59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
3005 32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
3006 59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
3007 46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
3008 97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
3009 46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
3010 119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
3011 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
3012 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3013 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
3014 119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
3015 59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
3016 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3017 32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
3018 81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
3019 87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
3020 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
3021 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
3022 45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
3023 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3024 32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
3025 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
3026 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
3027 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
3028 59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
3029 59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3030 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3031 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
3032 81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
3033 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3034 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3035 32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
3036 81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3037 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
3038 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
3039 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
3040 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3041 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3042 32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
3043 81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
3044 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
3045 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3046 58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
3047 61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3048 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3049 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
3050 81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
3051 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3052 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3053 32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
3054 81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3055 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
3056 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
3057 59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
3058 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3059 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3060 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
3061 58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
3062 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
3063 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
3064 61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
3065 59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
3066 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
3067 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
3068 32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
3069 61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3070 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3071 32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
3072 59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
3073 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
3074 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
3075 59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
3076 59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3077 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3078 32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
3079 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
3080 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
3081 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3082 46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
3083 46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3084 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
3085 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
3086 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
3087 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3088 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3089 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
3090 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
3091 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
3092 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
3093 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
3094 59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3095 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3096 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
3097 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
3098 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3099 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3100 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3101 32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
3102 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10
3103 };
3104