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