Command.cpp revision a125c937de06b1cc43368743592f47513eb88b76
1edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project// 2edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project// Copyright 2006 The Android Open Source Project 3edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project// 4edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project// Android Asset Packaging Tool main entry point. 5edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project// 6edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include "Main.h" 7edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include "Bundle.h" 8edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include "ResourceTable.h" 9edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include "XMLNode.h" 10edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project 11edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <utils/Log.h> 12edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <utils/threads.h> 13edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <utils/List.h> 14edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <utils/Errors.h> 15edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project 16edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <fcntl.h> 17edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project#include <errno.h> 18edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project 19edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectusing namespace android; 20edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project 21edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project/* 22edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project * Show version info. All the cool kids do it. 23edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project */ 24076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopianint doVersion(Bundle* bundle) 25edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project{ 26edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project if (bundle->getFileSpecCount() != 0) 27c666cae2d5995097ec49a87e375e2afdd92802b7Mathias Agopian printf("(ignoring extra arguments)\n"); 28076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian printf("Android Asset Packaging Tool, v0.2\n"); 29edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project 30e3c697fb929c856b59fa56a8e05a2a7eba187c3dMathias Agopian return 0; 311a4d883dcc1725892bfb5c28dec255a233186524Jamie Gennis} 32076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian 33edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project 3499c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall/* 351b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian * Open the file read only. The call fails if the file doesn't exist. 36875d8e1323536e16dcfc90c9674d7ad32116a69aMathias Agopian * 371b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian * Returns NULL on failure. 38da8d0a5c0cf9d41915d3b106cad4aaec3e767c11Mathias Agopian */ 390f2f5ff75b7b48ceb64270655ee6b62d09bf4d00Mathias AgopianZipFile* openReadOnly(const char* fileName) 40c7d14e247117392fbd44aa454622778a25c076aeMathias Agopian{ 4113127d8921356dff794250e04208c3ed60b3a3dfMathias Agopian ZipFile* zip; 421f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian status_t result; 43a49126087b4494f4ef50873f3a3f6727265f6621Mathias Agopian 44edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project zip = new ZipFile; 45a49126087b4494f4ef50873f3a3f6727265f6621Mathias Agopian result = zip->open(fileName, ZipFile::kOpenReadOnly); 46edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project if (result != NO_ERROR) { 47edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project if (result == NAME_NOT_FOUND) 48edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project fprintf(stderr, "ERROR: '%s' not found\n", fileName); 49edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project else if (result == PERMISSION_DENIED) 50edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project fprintf(stderr, "ERROR: '%s' access denied\n", fileName); 51edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project else 520f2f5ff75b7b48ceb64270655ee6b62d09bf4d00Mathias Agopian fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n", 53edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project fileName); 54dd3cb84cfbe8068790c6233b5829fae9c4a0ee93Jamie Gennis delete zip; 55ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall return NULL; 5619e872912af66c53a4350afcc333bbafaf6a2294Jesse Hall } 57dd3cb84cfbe8068790c6233b5829fae9c4a0ee93Jamie Gennis 58dd3cb84cfbe8068790c6233b5829fae9c4a0ee93Jamie Gennis return zip; 5999c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall} 60db89edc94bd2a78226b407f9f7261e202e7fa325Mathias Agopian 61a49126087b4494f4ef50873f3a3f6727265f6621Mathias Agopian/* 6292a979a92c34b7de609ce2b1662c73bb8a2728b9Mathias Agopian * Open the file read-write. The file will be created if it doesn't 63ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall * already exist and "okayToCreate" is set. 6427e2562868dcd3ad26f9b4677b64ae272941704eChih-Wei Huang * 6599c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall * Returns NULL on failure. 6692a979a92c34b7de609ce2b1662c73bb8a2728b9Mathias Agopian */ 6792a979a92c34b7de609ce2b1662c73bb8a2728b9Mathias AgopianZipFile* openReadWrite(const char* fileName, bool okayToCreate) 6892a979a92c34b7de609ce2b1662c73bb8a2728b9Mathias Agopian{ 6992a979a92c34b7de609ce2b1662c73bb8a2728b9Mathias Agopian ZipFile* zip = NULL; 7092a979a92c34b7de609ce2b1662c73bb8a2728b9Mathias Agopian status_t result; 71dd3cb84cfbe8068790c6233b5829fae9c4a0ee93Jamie Gennis int flags; 7292a979a92c34b7de609ce2b1662c73bb8a2728b9Mathias Agopian 7392a979a92c34b7de609ce2b1662c73bb8a2728b9Mathias Agopian flags = ZipFile::kOpenReadWrite; 7401e29054e672301e4adbbca15b3562a59a20f267Jesse Hall if (okayToCreate) 75da8d0a5c0cf9d41915d3b106cad4aaec3e767c11Mathias Agopian flags |= ZipFile::kOpenCreate; 76edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project 7783cafffeac037ab2f9d00f98f8d2f3da8fc9b857Jesse Hall zip = new ZipFile; 78a49126087b4494f4ef50873f3a3f6727265f6621Mathias Agopian result = zip->open(fileName, flags); 79a49126087b4494f4ef50873f3a3f6727265f6621Mathias Agopian if (result != NO_ERROR) { 80a49126087b4494f4ef50873f3a3f6727265f6621Mathias Agopian delete zip; 81a49126087b4494f4ef50873f3a3f6727265f6621Mathias Agopian zip = NULL; 82b5dd9c0fee3b3d6d35035dfb992951ebea3e0e4eMathias Agopian goto bail; 83385977f6d6c4e76379df384d50695a10cb3757f2Mathias Agopian } 841f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian 85a49126087b4494f4ef50873f3a3f6727265f6621Mathias Agopianbail: 86edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project return zip; 8719e872912af66c53a4350afcc333bbafaf6a2294Jesse Hall} 8819e872912af66c53a4350afcc333bbafaf6a2294Jesse Hall 8919e872912af66c53a4350afcc333bbafaf6a2294Jesse Hall 90a49126087b4494f4ef50873f3a3f6727265f6621Mathias Agopian/* 911b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian * Return a short string describing the compression method. 921b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian */ 93edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Projectconst char* compressionName(int method) 944ee5696dfbcea1078b24e7c089de74e7cf4e55caJohn Dong{ 954ee5696dfbcea1078b24e7c089de74e7cf4e55caJohn Dong if (method == ZipEntry::kCompressStored) 964ee5696dfbcea1078b24e7c089de74e7cf4e55caJohn Dong return "Stored"; 974ee5696dfbcea1078b24e7c089de74e7cf4e55caJohn Dong else if (method == ZipEntry::kCompressDeflated) 984ee5696dfbcea1078b24e7c089de74e7cf4e55caJohn Dong return "Deflated"; 994ee5696dfbcea1078b24e7c089de74e7cf4e55caJohn Dong else 1004ee5696dfbcea1078b24e7c089de74e7cf4e55caJohn Dong return "Unknown"; 1014ee5696dfbcea1078b24e7c089de74e7cf4e55caJohn Dong} 1024ee5696dfbcea1078b24e7c089de74e7cf4e55caJohn Dong 1034ee5696dfbcea1078b24e7c089de74e7cf4e55caJohn Dong/* 1041f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian * Return the percent reduction in size (0% == no compression). 1051f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian */ 106a49126087b4494f4ef50873f3a3f6727265f6621Mathias Agopianint calcPercent(long uncompressedLen, long compressedLen) 1071f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian{ 108da8d0a5c0cf9d41915d3b106cad4aaec3e767c11Mathias Agopian if (!uncompressedLen) 109da8d0a5c0cf9d41915d3b106cad4aaec3e767c11Mathias Agopian return 0; 1101f7bec634f19c123410a5155c8d282e177c01930Mathias Agopian else 111ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5); 112ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall} 1135f20e2d4462da3471f59152b32cd8640fa4a21daMathias Agopian 1148dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden/* 1158dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden * Handle the "list" command, which can be a simple file dump or 1168dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden * a verbose listing. 1178dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden * 1188dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden * The verbose listing closely matches the output of the Info-ZIP "unzip" 1198dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden * command. 1208dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden */ 1218dfa92fef9759a881e96ee58d59875d35023aab9Andy McFaddenint doList(Bundle* bundle) 1228dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden{ 1238dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden int result = 1; 1248dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden ZipFile* zip = NULL; 1258dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden const ZipEntry* entry; 1268dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden long totalUncLen, totalCompLen; 1278dfa92fef9759a881e96ee58d59875d35023aab9Andy McFadden const char* zipFileName; 12898a121aa916eb7acbf11df0e3e31a6fede6fc9ddMathias Agopian 12900e8c7a88a5b9c4104a71013a713acd3e4d3b77bMathias Agopian if (bundle->getFileSpecCount() != 1) { 130a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian fprintf(stderr, "ERROR: specify zip file name (only)\n"); 131a350ff98692b3a50cad5cc93f9f83221242ca86aMathias Agopian goto bail; 132ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall } 133ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall zipFileName = bundle->getFileSpecEntry(0); 134ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall 135ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall zip = openReadOnly(zipFileName); 136ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall if (zip == NULL) 137ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall goto bail; 138ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall 13902d86567d95b99e1142941ed7ec23a4465822813Jesse Hall int count, i; 14002d86567d95b99e1142941ed7ec23a4465822813Jesse Hall 14102d86567d95b99e1142941ed7ec23a4465822813Jesse Hall if (bundle->getVerbose()) { 14202d86567d95b99e1142941ed7ec23a4465822813Jesse Hall printf("Archive: %s\n", zipFileName); 14302d86567d95b99e1142941ed7ec23a4465822813Jesse Hall printf( 14402d86567d95b99e1142941ed7ec23a4465822813Jesse Hall " Length Method Size Ratio Offset Date Time CRC-32 Name\n"); 14502d86567d95b99e1142941ed7ec23a4465822813Jesse Hall printf( 14602d86567d95b99e1142941ed7ec23a4465822813Jesse Hall "-------- ------ ------- ----- ------- ---- ---- ------ ----\n"); 14702d86567d95b99e1142941ed7ec23a4465822813Jesse Hall } 148ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall 149ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall totalUncLen = totalCompLen = 0; 150ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall 151ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall count = zip->getNumEntries(); 152ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall for (i = 0; i < count; i++) { 153ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall entry = zip->getEntryByIndex(i); 154ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall if (bundle->getVerbose()) { 155ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall char dateBuf[32]; 156ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall time_t when; 157ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall 158ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall when = entry->getModWhen(); 159ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M", 160ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall localtime(&when)); 161ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall 162ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall printf("%8ld %-7.7s %7ld %3d%% %8zd %s %08lx %s\n", 163ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall (long) entry->getUncompressedLen(), 164ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall compressionName(entry->getCompressionMethod()), 165ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall (long) entry->getCompressedLen(), 166ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall calcPercent(entry->getUncompressedLen(), 167ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0aJesse Hall entry->getCompressedLen()), 1689e2463e71796964cfaa06bf09a880875ac3537bcMathias Agopian (size_t) entry->getLFHOffset(), 1699e2463e71796964cfaa06bf09a880875ac3537bcMathias Agopian dateBuf, 1709e2463e71796964cfaa06bf09a880875ac3537bcMathias Agopian entry->getCRC32(), 1719e2463e71796964cfaa06bf09a880875ac3537bcMathias Agopian entry->getFileName()); 1729e2463e71796964cfaa06bf09a880875ac3537bcMathias Agopian } else { 1739e2463e71796964cfaa06bf09a880875ac3537bcMathias Agopian printf("%s\n", entry->getFileName()); 1749e2463e71796964cfaa06bf09a880875ac3537bcMathias Agopian } 1750f2f5ff75b7b48ceb64270655ee6b62d09bf4d00Mathias Agopian 176076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian totalUncLen += entry->getUncompressedLen(); 177edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project totalCompLen += entry->getCompressedLen(); 178edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project } 1790f2f5ff75b7b48ceb64270655ee6b62d09bf4d00Mathias Agopian 18099c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall if (bundle->getVerbose()) { 18174faca212e2675aa55a30235c77cb6403471a4b9Mathias Agopian printf( 182edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project "-------- ------- --- -------\n"); 1830f2f5ff75b7b48ceb64270655ee6b62d09bf4d00Mathias Agopian printf("%8ld %7ld %2d%% %d files\n", 184edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project totalUncLen, 185875d8e1323536e16dcfc90c9674d7ad32116a69aMathias Agopian totalCompLen, 186edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project calcPercent(totalUncLen, totalCompLen), 187edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project zip->getNumEntries()); 188edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project } 189edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project 19001e29054e672301e4adbbca15b3562a59a20f267Jesse Hall if (bundle->getAndroidList()) { 191df3ca30bf663cb8eed88ee3f16fb5e9a65dc00fcMathias Agopian AssetManager assets; 192b8a5560e1303cb10f5cd482af466fc04d2bdfcabMathias Agopian if (!assets.addAssetPath(String8(zipFileName), NULL)) { 193b8a5560e1303cb10f5cd482af466fc04d2bdfcabMathias Agopian fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n"); 194df3ca30bf663cb8eed88ee3f16fb5e9a65dc00fcMathias Agopian goto bail; 195df3ca30bf663cb8eed88ee3f16fb5e9a65dc00fcMathias Agopian } 19601e29054e672301e4adbbca15b3562a59a20f267Jesse Hall 197c701401f8cec2e5309f8b57e2b97baced5093274Dan Stoza const ResTable& res = assets.getResources(false); 198c701401f8cec2e5309f8b57e2b97baced5093274Dan Stoza if (&res == NULL) { 1995e78e0965169790111f01354e78b0f8d34c94840Mathias Agopian printf("\nNo resource table found.\n"); 200d870703d5566490cfdfb389d9336b2b8d3c6cc7aMathias Agopian } else { 201076b1cc3a9b90aa5b381a1ed268ca0b548444c9bMathias Agopian#ifndef HAVE_ANDROID_OS 202edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project printf("\nResource table:\n"); 203edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project res.print(false); 2047143316af216fa92c31a60d4407b707637382da1Dan Stoza#endif 2057143316af216fa92c31a60d4407b707637382da1Dan Stoza } 206028dc8f2d72bc7cd4fbe7808781443125a742f78Jesse Hall 207028dc8f2d72bc7cd4fbe7808781443125a742f78Jesse Hall Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml", 20838efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall Asset::ACCESS_BUFFER); 20938efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall if (manifestAsset == NULL) { 21038efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall printf("\nNo AndroidManifest.xml found.\n"); 21138efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall } else { 21238efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall printf("\nAndroid manifest:\n"); 21338efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall ResXMLTree tree; 21438efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall tree.setTo(manifestAsset->getBuffer(true), 21538efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall manifestAsset->getLength()); 21638efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall printXMLBlock(&tree); 21738efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall } 21838efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall delete manifestAsset; 21938efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall } 22038efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall 22138efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall result = 0; 22238efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall 22338efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hallbail: 22438efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall delete zip; 22538efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall return result; 22638efe86d9459cf5c96a24a34cc5cbf31fdba7e19Jesse Hall} 227da27af9832a0170f1fc40ef3f21371c4d30d21b3Mathias Agopian 22822a99f0fc2884227b9d7e46959fcbe6270667efbAndy McFaddenstatic ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes) 22922a99f0fc2884227b9d7e46959fcbe6270667efbAndy McFadden{ 23022a99f0fc2884227b9d7e46959fcbe6270667efbAndy McFadden size_t N = tree.getAttributeCount(); 23122a99f0fc2884227b9d7e46959fcbe6270667efbAndy McFadden for (size_t i=0; i<N; i++) { 23222a99f0fc2884227b9d7e46959fcbe6270667efbAndy McFadden if (tree.getAttributeNameResID(i) == attrRes) { 23322a99f0fc2884227b9d7e46959fcbe6270667efbAndy McFadden return (ssize_t)i; 23499c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall } 23599c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall } 23622a99f0fc2884227b9d7e46959fcbe6270667efbAndy McFadden return -1; 23799c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall} 23899c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall 23999c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse HallString8 getAttribute(const ResXMLTree& tree, const char* ns, 24099c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall const char* attr, String8* outError) 24199c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall{ 24299c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall ssize_t idx = tree.indexOfAttribute(ns, attr); 24399c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall if (idx < 0) { 24499c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall return String8(); 24599c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall } 24699c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall Res_value value; 247da27af9832a0170f1fc40ef3f21371c4d30d21b3Mathias Agopian if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 248da27af9832a0170f1fc40ef3f21371c4d30d21b3Mathias Agopian if (value.dataType != Res_value::TYPE_STRING) { 249da27af9832a0170f1fc40ef3f21371c4d30d21b3Mathias Agopian if (outError != NULL) *outError = "attribute is not a string value"; 25052e21483fa48baeb4a88372d75e083bca2e92923Mathias Agopian return String8(); 25199c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall } 25299c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall } 25399c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall size_t len; 25499c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall const uint16_t* str = tree.getAttributeStringValue(idx, &len); 25532341381c9493d7953e40f7f79653cfc52868863Mathias Agopian return str ? String8(str, len) : String8(); 256da27af9832a0170f1fc40ef3f21371c4d30d21b3Mathias Agopian} 257da27af9832a0170f1fc40ef3f21371c4d30d21b3Mathias Agopian 258da27af9832a0170f1fc40ef3f21371c4d30d21b3Mathias Agopianstatic String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError) 259da27af9832a0170f1fc40ef3f21371c4d30d21b3Mathias Agopian{ 260851cfe834295224cd64bdd499872b95b19c4de8cJesse Hall ssize_t idx = indexOfAttribute(tree, attrRes); 261da27af9832a0170f1fc40ef3f21371c4d30d21b3Mathias Agopian if (idx < 0) { 262da27af9832a0170f1fc40ef3f21371c4d30d21b3Mathias Agopian return String8(); 263da27af9832a0170f1fc40ef3f21371c4d30d21b3Mathias Agopian } 2640f2f5ff75b7b48ceb64270655ee6b62d09bf4d00Mathias Agopian Res_value value; 265edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 266edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project if (value.dataType != Res_value::TYPE_STRING) { 267edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project if (outError != NULL) *outError = "attribute is not a string value"; 268edbf3b6af777b721cd2a1ef461947e51e88241e1The Android Open Source Project return String8(); 269875d8e1323536e16dcfc90c9674d7ad32116a69aMathias Agopian } 270da8d0a5c0cf9d41915d3b106cad4aaec3e767c11Mathias Agopian } 27152bbb1ae239c8a4d05543a23fa8c08467d09c3b2Mathias Agopian size_t len; 272875d8e1323536e16dcfc90c9674d7ad32116a69aMathias Agopian const uint16_t* str = tree.getAttributeStringValue(idx, &len); 273875d8e1323536e16dcfc90c9674d7ad32116a69aMathias Agopian return str ? String8(str, len) : String8(); 274da8d0a5c0cf9d41915d3b106cad4aaec3e767c11Mathias Agopian} 275f460f55c84b0a75de749b8a784059f5ff423ed93Jesse Hall 276f460f55c84b0a75de749b8a784059f5ff423ed93Jesse Hallstatic int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, 277da8d0a5c0cf9d41915d3b106cad4aaec3e767c11Mathias Agopian String8* outError, int32_t defValue = -1) 27852bbb1ae239c8a4d05543a23fa8c08467d09c3b2Mathias Agopian{ 279931bda1c472ba8c8e965bdba6757ff94154df903Mathias Agopian ssize_t idx = indexOfAttribute(tree, attrRes); 280da8d0a5c0cf9d41915d3b106cad4aaec3e767c11Mathias Agopian if (idx < 0) { 28152bbb1ae239c8a4d05543a23fa8c08467d09c3b2Mathias Agopian return defValue; 28252bbb1ae239c8a4d05543a23fa8c08467d09c3b2Mathias Agopian } 283875d8e1323536e16dcfc90c9674d7ad32116a69aMathias Agopian Res_value value; 284875d8e1323536e16dcfc90c9674d7ad32116a69aMathias Agopian if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 285875d8e1323536e16dcfc90c9674d7ad32116a69aMathias Agopian if (value.dataType < Res_value::TYPE_FIRST_INT 286c18790018be5d7ea7061ccbc81f3044e74adc823Dan Stoza || value.dataType > Res_value::TYPE_LAST_INT) { 287c18790018be5d7ea7061ccbc81f3044e74adc823Dan Stoza if (outError != NULL) *outError = "attribute is not an integer value"; 288bae92d0d605e99a14731add4f11b72413b2835e5Mathias Agopian return defValue; 289bae92d0d605e99a14731add4f11b72413b2835e5Mathias Agopian } 2901b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian } 2911b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian return value.data; 29213127d8921356dff794250e04208c3ed60b3a3dfMathias Agopian} 2933b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian 294ef7b9c7eac036cc1230c64821039d18f8cbd2c1cMathias Agopianstatic int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree, 2953b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian uint32_t attrRes, String8* outError, int32_t defValue = -1) 2963b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian{ 29713127d8921356dff794250e04208c3ed60b3a3dfMathias Agopian ssize_t idx = indexOfAttribute(tree, attrRes); 298f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian if (idx < 0) { 2993b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian return defValue; 3003b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian } 3013b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian Res_value value; 3023b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 3033b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian if (value.dataType == Res_value::TYPE_REFERENCE) { 30413127d8921356dff794250e04208c3ed60b3a3dfMathias Agopian resTable->resolveReference(&value, 0); 3053b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian } 3063b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian if (value.dataType < Res_value::TYPE_FIRST_INT 3073b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian || value.dataType > Res_value::TYPE_LAST_INT) { 3080f2f5ff75b7b48ceb64270655ee6b62d09bf4d00Mathias Agopian if (outError != NULL) *outError = "attribute is not an integer value"; 3093b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian return defValue; 3103b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian } 3113b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian } 312cd60f99aba9e750700a967db30b74a29145739cfMathias Agopian return value.data; 313cd60f99aba9e750700a967db30b74a29145739cfMathias Agopian} 314cd60f99aba9e750700a967db30b74a29145739cfMathias Agopian 315cd60f99aba9e750700a967db30b74a29145739cfMathias Agopianstatic String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree, 316cd60f99aba9e750700a967db30b74a29145739cfMathias Agopian uint32_t attrRes, String8* outError) 317da8d0a5c0cf9d41915d3b106cad4aaec3e767c11Mathias Agopian{ 318cd60f99aba9e750700a967db30b74a29145739cfMathias Agopian ssize_t idx = indexOfAttribute(tree, attrRes); 319cd60f99aba9e750700a967db30b74a29145739cfMathias Agopian if (idx < 0) { 320cd60f99aba9e750700a967db30b74a29145739cfMathias Agopian return String8(); 321cd60f99aba9e750700a967db30b74a29145739cfMathias Agopian } 322cd60f99aba9e750700a967db30b74a29145739cfMathias Agopian Res_value value; 323cd60f99aba9e750700a967db30b74a29145739cfMathias Agopian if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 3243b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopian if (value.dataType == Res_value::TYPE_STRING) { 325d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian size_t len; 326d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian const uint16_t* str = tree.getAttributeStringValue(idx, &len); 327d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian return str ? String8(str, len) : String8(); 328d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian } 329d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian resTable->resolveReference(&value, 0); 330d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian if (value.dataType != Res_value::TYPE_STRING) { 331d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian if (outError != NULL) *outError = "attribute is not a string value"; 332d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian return String8(); 333d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian } 334d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian } 335d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian size_t len; 336d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian const Res_value* value2 = &value; 337d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len); 338d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian return str ? String8(str, len) : String8(); 339d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian} 340d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian 341d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian// These are attribute resource constants for the platform, as found 342d3ee231eddce0b69ec5e35188dbd0f4a2c3b9ac3Mathias Agopian// in android.R.attr 3433b1d2b6b2bbfb5df46b1059ec52360974e6f1428Mathias Agopianenum { 34428947d7fbf9f486539322e8e12dd057568e180c2Mathias Agopian LABEL_ATTR = 0x01010001, 34528947d7fbf9f486539322e8e12dd057568e180c2Mathias Agopian ICON_ATTR = 0x01010002, 34628947d7fbf9f486539322e8e12dd057568e180c2Mathias Agopian NAME_ATTR = 0x01010003, 34728947d7fbf9f486539322e8e12dd057568e180c2Mathias Agopian VERSION_CODE_ATTR = 0x0101021b, 34828947d7fbf9f486539322e8e12dd057568e180c2Mathias Agopian VERSION_NAME_ATTR = 0x0101021c, 34928947d7fbf9f486539322e8e12dd057568e180c2Mathias Agopian SCREEN_ORIENTATION_ATTR = 0x0101001e, 35028947d7fbf9f486539322e8e12dd057568e180c2Mathias Agopian MIN_SDK_VERSION_ATTR = 0x0101020c, 351c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian MAX_SDK_VERSION_ATTR = 0x01010271, 352c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian REQ_TOUCH_SCREEN_ATTR = 0x01010227, 353c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian REQ_KEYBOARD_TYPE_ATTR = 0x01010228, 354c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian REQ_HARD_KEYBOARD_ATTR = 0x01010229, 355c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian REQ_NAVIGATION_ATTR = 0x0101022a, 356c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian REQ_FIVE_WAY_NAV_ATTR = 0x01010232, 357c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian TARGET_SDK_VERSION_ATTR = 0x01010270, 358c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian TEST_ONLY_ATTR = 0x01010272, 359c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian ANY_DENSITY_ATTR = 0x0101026c, 360c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian GL_ES_VERSION_ATTR = 0x01010281, 361c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian SMALL_SCREEN_ATTR = 0x01010284, 362c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian NORMAL_SCREEN_ATTR = 0x01010285, 363c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian LARGE_SCREEN_ATTR = 0x01010286, 364c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian XLARGE_SCREEN_ATTR = 0x010102bf, 365c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian REQUIRED_ATTR = 0x0101028e, 366c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian SCREEN_SIZE_ATTR = 0x010102ca, 367c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian SCREEN_DENSITY_ATTR = 0x010102cb, 368c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364, 369c1c05de415854eb7a13a16b7e22a22de8515123aMathias Agopian COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365, 3700f2f5ff75b7b48ceb64270655ee6b62d09bf4d00Mathias Agopian LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366, 3711b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian}; 3721b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian 3731b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopianconst char *getComponentName(String8 &pkgName, String8 &componentName) { 3741b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian ssize_t idx = componentName.find("."); 3753165cc21cfea781988407b19bd83292b19f05f55Mathias Agopian String8 retStr(pkgName); 3761b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian if (idx == 0) { 3771b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian retStr += componentName; 3783165cc21cfea781988407b19bd83292b19f05f55Mathias Agopian } else if (idx < 0) { 3791b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian retStr += "."; 3801b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian retStr += componentName; 3813165cc21cfea781988407b19bd83292b19f05f55Mathias Agopian } else { 3821b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian return componentName.string(); 3831b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian } 3843165cc21cfea781988407b19bd83292b19f05f55Mathias Agopian return retStr.string(); 3851b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian} 3861b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian 3871b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopianstatic void printCompatibleScreens(ResXMLTree& tree) { 3881b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian size_t len; 3891b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian ResXMLTree::event_code_t code; 3901b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian int depth = 0; 3911b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian bool first = true; 3921b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian printf("compatible-screens:"); 3931b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { 39400e8c7a88a5b9c4104a71013a713acd3e4d3b77bMathias Agopian if (code == ResXMLTree::END_TAG) { 395f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian depth--; 396f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian if (depth < 0) { 397f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian break; 398da8d0a5c0cf9d41915d3b106cad4aaec3e767c11Mathias Agopian } 399f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian continue; 400f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian } 401da8d0a5c0cf9d41915d3b106cad4aaec3e767c11Mathias Agopian if (code != ResXMLTree::START_TAG) { 402f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian continue; 403f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian } 4041b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian depth++; 405f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian String8 tag(tree.getElementName(&len)); 406f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian if (tag == "screen") { 407f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian int32_t screenSize = getIntegerAttribute(tree, 408f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian SCREEN_SIZE_ATTR, NULL, -1); 409f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian int32_t screenDensity = getIntegerAttribute(tree, 4106360ec42d414b1351ecb6c5fc4b8afa30d8f4ebfJesse Hall SCREEN_DENSITY_ATTR, NULL, -1); 411f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian if (screenSize > 0 && screenDensity > 0) { 412f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian if (!first) { 413f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian printf(","); 414f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian } 415f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian first = false; 416f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian printf("'%d/%d'", screenSize, screenDensity); 417f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian } 418f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian } 419f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian } 420f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian printf("\n"); 421766dc49c17dda977bf7b93a5fd8da41c0b737611Mathias Agopian} 4221b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian 423f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian/* 424f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian * Handle the "dump" command, to extract select data from an archive. 425f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian */ 426f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopianint doDump(Bundle* bundle) 427f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian{ 428f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian status_t result = UNKNOWN_ERROR; 429f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian Asset* asset = NULL; 430f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian 431f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian if (bundle->getFileSpecCount() < 1) { 432f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian fprintf(stderr, "ERROR: no dump option specified\n"); 433f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian return 1; 434f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian } 435f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian 436f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian if (bundle->getFileSpecCount() < 2) { 437f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian fprintf(stderr, "ERROR: no dump file specified\n"); 438f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian return 1; 439f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian } 440f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian 441f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian const char* option = bundle->getFileSpecEntry(0); 442f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian const char* filename = bundle->getFileSpecEntry(1); 443f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian 444f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian AssetManager assets; 445f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian void* assetsCookie; 446f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian if (!assets.addAssetPath(String8(filename), &assetsCookie)) { 447f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n"); 448f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian return 1; 449f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian } 450f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian 451f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian // Make a dummy config for retrieving resources... we need to supply 452f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian // non-default values for some configs so that we can retrieve resources 453f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian // in the app that don't have a default. The most important of these is 454f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian // the API version because key resources like icons will have an implicit 4556c7f25afb75ac155bad0b3bc17c0089d0337d060Mathias Agopian // version if they are using newer config types like density. 456f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian ResTable_config config; 457f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian config.language[0] = 'e'; 458f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian config.language[1] = 'n'; 459f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian config.country[0] = 'U'; 460f5f714aa188884098aaecbe39d0bc61b40311c0dMathias Agopian config.country[1] = 'S'; 4611b03149f3533db04e72e088d3fdd09d0087ca594Mathias Agopian config.orientation = ResTable_config::ORIENTATION_PORT; 4621d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian config.density = ResTable_config::DENSITY_MEDIUM; 46374d211ae26a0257c6075a823812e40b55aa1e653Mathias Agopian config.sdkVersion = 10000; // Very high. 4641d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian config.screenWidthDp = 320; 46574d211ae26a0257c6075a823812e40b55aa1e653Mathias Agopian config.screenHeightDp = 480; 4661d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian config.smallestScreenWidthDp = 320; 46702d86567d95b99e1142941ed7ec23a4465822813Jesse Hall assets.setConfiguration(config); 46886efcc0cbc1d94250b72ef1f2ea8700a04cd2781Greg Hackmann 469766dc49c17dda977bf7b93a5fd8da41c0b737611Mathias Agopian const ResTable& res = assets.getResources(false); 4701d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian if (&res == NULL) { 47102d86567d95b99e1142941ed7ec23a4465822813Jesse Hall fprintf(stderr, "ERROR: dump failed because no resource table was found\n"); 4721d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian goto bail; 4731d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian } 474dd3cb84cfbe8068790c6233b5829fae9c4a0ee93Jamie Gennis 4751d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian if (strcmp("resources", option) == 0) { 4761d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian#ifndef HAVE_ANDROID_OS 477766dc49c17dda977bf7b93a5fd8da41c0b737611Mathias Agopian res.print(bundle->getValues()); 4781d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian#endif 4791d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian } else if (strcmp("xmltree", option) == 0) { 4801d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian if (bundle->getFileSpecCount() < 3) { 4811d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); 48299c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall goto bail; 48399c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall } 48499c7dbb24994df2f3e175f7b25dd2c9dd92a72f0Jesse Hall 4851d12d8a8e61163b35cf42c51c558a67138014e82Mathias Agopian for (int i=2; i<bundle->getFileSpecCount(); i++) { 486 const char* resname = bundle->getFileSpecEntry(i); 487 ResXMLTree tree; 488 asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); 489 if (asset == NULL) { 490 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); 491 goto bail; 492 } 493 494 if (tree.setTo(asset->getBuffer(true), 495 asset->getLength()) != NO_ERROR) { 496 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); 497 goto bail; 498 } 499 tree.restart(); 500 printXMLBlock(&tree); 501 tree.uninit(); 502 delete asset; 503 asset = NULL; 504 } 505 506 } else if (strcmp("xmlstrings", option) == 0) { 507 if (bundle->getFileSpecCount() < 3) { 508 fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); 509 goto bail; 510 } 511 512 for (int i=2; i<bundle->getFileSpecCount(); i++) { 513 const char* resname = bundle->getFileSpecEntry(i); 514 ResXMLTree tree; 515 asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); 516 if (asset == NULL) { 517 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); 518 goto bail; 519 } 520 521 if (tree.setTo(asset->getBuffer(true), 522 asset->getLength()) != NO_ERROR) { 523 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); 524 goto bail; 525 } 526 printStringPool(&tree.getStrings()); 527 delete asset; 528 asset = NULL; 529 } 530 531 } else { 532 ResXMLTree tree; 533 asset = assets.openNonAsset("AndroidManifest.xml", 534 Asset::ACCESS_BUFFER); 535 if (asset == NULL) { 536 fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n"); 537 goto bail; 538 } 539 540 if (tree.setTo(asset->getBuffer(true), 541 asset->getLength()) != NO_ERROR) { 542 fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n"); 543 goto bail; 544 } 545 tree.restart(); 546 547 if (strcmp("permissions", option) == 0) { 548 size_t len; 549 ResXMLTree::event_code_t code; 550 int depth = 0; 551 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { 552 if (code == ResXMLTree::END_TAG) { 553 depth--; 554 continue; 555 } 556 if (code != ResXMLTree::START_TAG) { 557 continue; 558 } 559 depth++; 560 String8 tag(tree.getElementName(&len)); 561 //printf("Depth %d tag %s\n", depth, tag.string()); 562 if (depth == 1) { 563 if (tag != "manifest") { 564 fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); 565 goto bail; 566 } 567 String8 pkg = getAttribute(tree, NULL, "package", NULL); 568 printf("package: %s\n", pkg.string()); 569 } else if (depth == 2 && tag == "permission") { 570 String8 error; 571 String8 name = getAttribute(tree, NAME_ATTR, &error); 572 if (error != "") { 573 fprintf(stderr, "ERROR: %s\n", error.string()); 574 goto bail; 575 } 576 printf("permission: %s\n", name.string()); 577 } else if (depth == 2 && tag == "uses-permission") { 578 String8 error; 579 String8 name = getAttribute(tree, NAME_ATTR, &error); 580 if (error != "") { 581 fprintf(stderr, "ERROR: %s\n", error.string()); 582 goto bail; 583 } 584 printf("uses-permission: %s\n", name.string()); 585 } 586 } 587 } else if (strcmp("badging", option) == 0) { 588 Vector<String8> locales; 589 res.getLocales(&locales); 590 591 Vector<ResTable_config> configs; 592 res.getConfigurations(&configs); 593 SortedVector<int> densities; 594 const size_t NC = configs.size(); 595 for (size_t i=0; i<NC; i++) { 596 int dens = configs[i].density; 597 if (dens == 0) dens = 160; 598 densities.add(dens); 599 } 600 601 size_t len; 602 ResXMLTree::event_code_t code; 603 int depth = 0; 604 String8 error; 605 bool withinActivity = false; 606 bool isMainActivity = false; 607 bool isLauncherActivity = false; 608 bool isSearchable = false; 609 bool withinApplication = false; 610 bool withinReceiver = false; 611 bool withinService = false; 612 bool withinIntentFilter = false; 613 bool hasMainActivity = false; 614 bool hasOtherActivities = false; 615 bool hasOtherReceivers = false; 616 bool hasOtherServices = false; 617 bool hasWallpaperService = false; 618 bool hasImeService = false; 619 bool hasWidgetReceivers = false; 620 bool hasIntentFilter = false; 621 bool actMainActivity = false; 622 bool actWidgetReceivers = false; 623 bool actImeService = false; 624 bool actWallpaperService = false; 625 626 // This next group of variables is used to implement a group of 627 // backward-compatibility heuristics necessitated by the addition of 628 // some new uses-feature constants in 2.1 and 2.2. In most cases, the 629 // heuristic is "if an app requests a permission but doesn't explicitly 630 // request the corresponding <uses-feature>, presume it's there anyway". 631 bool specCameraFeature = false; // camera-related 632 bool specCameraAutofocusFeature = false; 633 bool reqCameraAutofocusFeature = false; 634 bool reqCameraFlashFeature = false; 635 bool hasCameraPermission = false; 636 bool specLocationFeature = false; // location-related 637 bool specNetworkLocFeature = false; 638 bool reqNetworkLocFeature = false; 639 bool specGpsFeature = false; 640 bool reqGpsFeature = false; 641 bool hasMockLocPermission = false; 642 bool hasCoarseLocPermission = false; 643 bool hasGpsPermission = false; 644 bool hasGeneralLocPermission = false; 645 bool specBluetoothFeature = false; // Bluetooth API-related 646 bool hasBluetoothPermission = false; 647 bool specMicrophoneFeature = false; // microphone-related 648 bool hasRecordAudioPermission = false; 649 bool specWiFiFeature = false; 650 bool hasWiFiPermission = false; 651 bool specTelephonyFeature = false; // telephony-related 652 bool reqTelephonySubFeature = false; 653 bool hasTelephonyPermission = false; 654 bool specTouchscreenFeature = false; // touchscreen-related 655 bool specMultitouchFeature = false; 656 bool reqDistinctMultitouchFeature = false; 657 bool specScreenPortraitFeature = false; 658 bool specScreenLandscapeFeature = false; 659 bool reqScreenPortraitFeature = false; 660 bool reqScreenLandscapeFeature = false; 661 // 2.2 also added some other features that apps can request, but that 662 // have no corresponding permission, so we cannot implement any 663 // back-compatibility heuristic for them. The below are thus unnecessary 664 // (but are retained here for documentary purposes.) 665 //bool specCompassFeature = false; 666 //bool specAccelerometerFeature = false; 667 //bool specProximityFeature = false; 668 //bool specAmbientLightFeature = false; 669 //bool specLiveWallpaperFeature = false; 670 671 int targetSdk = 0; 672 int smallScreen = 1; 673 int normalScreen = 1; 674 int largeScreen = 1; 675 int xlargeScreen = 1; 676 int anyDensity = 1; 677 int requiresSmallestWidthDp = 0; 678 int compatibleWidthLimitDp = 0; 679 int largestWidthLimitDp = 0; 680 String8 pkg; 681 String8 activityName; 682 String8 activityLabel; 683 String8 activityIcon; 684 String8 receiverName; 685 String8 serviceName; 686 while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { 687 if (code == ResXMLTree::END_TAG) { 688 depth--; 689 if (depth < 2) { 690 withinApplication = false; 691 } else if (depth < 3) { 692 if (withinActivity && isMainActivity && isLauncherActivity) { 693 const char *aName = getComponentName(pkg, activityName); 694 printf("launchable-activity:"); 695 if (aName != NULL) { 696 printf(" name='%s' ", aName); 697 } 698 printf(" label='%s' icon='%s'\n", 699 activityLabel.string(), 700 activityIcon.string()); 701 } 702 if (!hasIntentFilter) { 703 hasOtherActivities |= withinActivity; 704 hasOtherReceivers |= withinReceiver; 705 hasOtherServices |= withinService; 706 } 707 withinActivity = false; 708 withinService = false; 709 withinReceiver = false; 710 hasIntentFilter = false; 711 isMainActivity = isLauncherActivity = false; 712 } else if (depth < 4) { 713 if (withinIntentFilter) { 714 if (withinActivity) { 715 hasMainActivity |= actMainActivity; 716 hasOtherActivities |= !actMainActivity; 717 } else if (withinReceiver) { 718 hasWidgetReceivers |= actWidgetReceivers; 719 hasOtherReceivers |= !actWidgetReceivers; 720 } else if (withinService) { 721 hasImeService |= actImeService; 722 hasWallpaperService |= actWallpaperService; 723 hasOtherServices |= (!actImeService && !actWallpaperService); 724 } 725 } 726 withinIntentFilter = false; 727 } 728 continue; 729 } 730 if (code != ResXMLTree::START_TAG) { 731 continue; 732 } 733 depth++; 734 String8 tag(tree.getElementName(&len)); 735 //printf("Depth %d, %s\n", depth, tag.string()); 736 if (depth == 1) { 737 if (tag != "manifest") { 738 fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); 739 goto bail; 740 } 741 pkg = getAttribute(tree, NULL, "package", NULL); 742 printf("package: name='%s' ", pkg.string()); 743 int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error); 744 if (error != "") { 745 fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string()); 746 goto bail; 747 } 748 if (versionCode > 0) { 749 printf("versionCode='%d' ", versionCode); 750 } else { 751 printf("versionCode='' "); 752 } 753 String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error); 754 if (error != "") { 755 fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string()); 756 goto bail; 757 } 758 printf("versionName='%s'\n", versionName.string()); 759 } else if (depth == 2) { 760 withinApplication = false; 761 if (tag == "application") { 762 withinApplication = true; 763 764 String8 label; 765 const size_t NL = locales.size(); 766 for (size_t i=0; i<NL; i++) { 767 const char* localeStr = locales[i].string(); 768 assets.setLocale(localeStr != NULL ? localeStr : ""); 769 String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); 770 if (llabel != "") { 771 if (localeStr == NULL || strlen(localeStr) == 0) { 772 label = llabel; 773 printf("application-label:'%s'\n", llabel.string()); 774 } else { 775 if (label == "") { 776 label = llabel; 777 } 778 printf("application-label-%s:'%s'\n", localeStr, 779 llabel.string()); 780 } 781 } 782 } 783 784 ResTable_config tmpConfig = config; 785 const size_t ND = densities.size(); 786 for (size_t i=0; i<ND; i++) { 787 tmpConfig.density = densities[i]; 788 assets.setConfiguration(tmpConfig); 789 String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 790 if (icon != "") { 791 printf("application-icon-%d:'%s'\n", densities[i], icon.string()); 792 } 793 } 794 assets.setConfiguration(config); 795 796 String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 797 if (error != "") { 798 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); 799 goto bail; 800 } 801 int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0); 802 if (error != "") { 803 fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string()); 804 goto bail; 805 } 806 printf("application: label='%s' ", label.string()); 807 printf("icon='%s'\n", icon.string()); 808 if (testOnly != 0) { 809 printf("testOnly='%d'\n", testOnly); 810 } 811 } else if (tag == "uses-sdk") { 812 int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error); 813 if (error != "") { 814 error = ""; 815 String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error); 816 if (error != "") { 817 fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n", 818 error.string()); 819 goto bail; 820 } 821 if (name == "Donut") targetSdk = 4; 822 printf("sdkVersion:'%s'\n", name.string()); 823 } else if (code != -1) { 824 targetSdk = code; 825 printf("sdkVersion:'%d'\n", code); 826 } 827 code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1); 828 if (code != -1) { 829 printf("maxSdkVersion:'%d'\n", code); 830 } 831 code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error); 832 if (error != "") { 833 error = ""; 834 String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error); 835 if (error != "") { 836 fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n", 837 error.string()); 838 goto bail; 839 } 840 if (name == "Donut" && targetSdk < 4) targetSdk = 4; 841 printf("targetSdkVersion:'%s'\n", name.string()); 842 } else if (code != -1) { 843 if (targetSdk < code) { 844 targetSdk = code; 845 } 846 printf("targetSdkVersion:'%d'\n", code); 847 } 848 } else if (tag == "uses-configuration") { 849 int32_t reqTouchScreen = getIntegerAttribute(tree, 850 REQ_TOUCH_SCREEN_ATTR, NULL, 0); 851 int32_t reqKeyboardType = getIntegerAttribute(tree, 852 REQ_KEYBOARD_TYPE_ATTR, NULL, 0); 853 int32_t reqHardKeyboard = getIntegerAttribute(tree, 854 REQ_HARD_KEYBOARD_ATTR, NULL, 0); 855 int32_t reqNavigation = getIntegerAttribute(tree, 856 REQ_NAVIGATION_ATTR, NULL, 0); 857 int32_t reqFiveWayNav = getIntegerAttribute(tree, 858 REQ_FIVE_WAY_NAV_ATTR, NULL, 0); 859 printf("uses-configuration:"); 860 if (reqTouchScreen != 0) { 861 printf(" reqTouchScreen='%d'", reqTouchScreen); 862 } 863 if (reqKeyboardType != 0) { 864 printf(" reqKeyboardType='%d'", reqKeyboardType); 865 } 866 if (reqHardKeyboard != 0) { 867 printf(" reqHardKeyboard='%d'", reqHardKeyboard); 868 } 869 if (reqNavigation != 0) { 870 printf(" reqNavigation='%d'", reqNavigation); 871 } 872 if (reqFiveWayNav != 0) { 873 printf(" reqFiveWayNav='%d'", reqFiveWayNav); 874 } 875 printf("\n"); 876 } else if (tag == "supports-screens") { 877 smallScreen = getIntegerAttribute(tree, 878 SMALL_SCREEN_ATTR, NULL, 1); 879 normalScreen = getIntegerAttribute(tree, 880 NORMAL_SCREEN_ATTR, NULL, 1); 881 largeScreen = getIntegerAttribute(tree, 882 LARGE_SCREEN_ATTR, NULL, 1); 883 xlargeScreen = getIntegerAttribute(tree, 884 XLARGE_SCREEN_ATTR, NULL, 1); 885 anyDensity = getIntegerAttribute(tree, 886 ANY_DENSITY_ATTR, NULL, 1); 887 requiresSmallestWidthDp = getIntegerAttribute(tree, 888 REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0); 889 compatibleWidthLimitDp = getIntegerAttribute(tree, 890 COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0); 891 largestWidthLimitDp = getIntegerAttribute(tree, 892 LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0); 893 } else if (tag == "uses-feature") { 894 String8 name = getAttribute(tree, NAME_ATTR, &error); 895 896 if (name != "" && error == "") { 897 int req = getIntegerAttribute(tree, 898 REQUIRED_ATTR, NULL, 1); 899 900 if (name == "android.hardware.camera") { 901 specCameraFeature = true; 902 } else if (name == "android.hardware.camera.autofocus") { 903 // these have no corresponding permission to check for, 904 // but should imply the foundational camera permission 905 reqCameraAutofocusFeature = reqCameraAutofocusFeature || req; 906 specCameraAutofocusFeature = true; 907 } else if (req && (name == "android.hardware.camera.flash")) { 908 // these have no corresponding permission to check for, 909 // but should imply the foundational camera permission 910 reqCameraFlashFeature = true; 911 } else if (name == "android.hardware.location") { 912 specLocationFeature = true; 913 } else if (name == "android.hardware.location.network") { 914 specNetworkLocFeature = true; 915 reqNetworkLocFeature = reqNetworkLocFeature || req; 916 } else if (name == "android.hardware.location.gps") { 917 specGpsFeature = true; 918 reqGpsFeature = reqGpsFeature || req; 919 } else if (name == "android.hardware.bluetooth") { 920 specBluetoothFeature = true; 921 } else if (name == "android.hardware.touchscreen") { 922 specTouchscreenFeature = true; 923 } else if (name == "android.hardware.touchscreen.multitouch") { 924 specMultitouchFeature = true; 925 } else if (name == "android.hardware.touchscreen.multitouch.distinct") { 926 reqDistinctMultitouchFeature = reqDistinctMultitouchFeature || req; 927 } else if (name == "android.hardware.microphone") { 928 specMicrophoneFeature = true; 929 } else if (name == "android.hardware.wifi") { 930 specWiFiFeature = true; 931 } else if (name == "android.hardware.telephony") { 932 specTelephonyFeature = true; 933 } else if (req && (name == "android.hardware.telephony.gsm" || 934 name == "android.hardware.telephony.cdma")) { 935 // these have no corresponding permission to check for, 936 // but should imply the foundational telephony permission 937 reqTelephonySubFeature = true; 938 } else if (name == "android.hardware.screen.portrait") { 939 specScreenPortraitFeature = true; 940 } else if (name == "android.hardware.screen.landscape") { 941 specScreenLandscapeFeature = true; 942 } 943 printf("uses-feature%s:'%s'\n", 944 req ? "" : "-not-required", name.string()); 945 } else { 946 int vers = getIntegerAttribute(tree, 947 GL_ES_VERSION_ATTR, &error); 948 if (error == "") { 949 printf("uses-gl-es:'0x%x'\n", vers); 950 } 951 } 952 } else if (tag == "uses-permission") { 953 String8 name = getAttribute(tree, NAME_ATTR, &error); 954 if (name != "" && error == "") { 955 if (name == "android.permission.CAMERA") { 956 hasCameraPermission = true; 957 } else if (name == "android.permission.ACCESS_FINE_LOCATION") { 958 hasGpsPermission = true; 959 } else if (name == "android.permission.ACCESS_MOCK_LOCATION") { 960 hasMockLocPermission = true; 961 } else if (name == "android.permission.ACCESS_COARSE_LOCATION") { 962 hasCoarseLocPermission = true; 963 } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" || 964 name == "android.permission.INSTALL_LOCATION_PROVIDER") { 965 hasGeneralLocPermission = true; 966 } else if (name == "android.permission.BLUETOOTH" || 967 name == "android.permission.BLUETOOTH_ADMIN") { 968 hasBluetoothPermission = true; 969 } else if (name == "android.permission.RECORD_AUDIO") { 970 hasRecordAudioPermission = true; 971 } else if (name == "android.permission.ACCESS_WIFI_STATE" || 972 name == "android.permission.CHANGE_WIFI_STATE" || 973 name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") { 974 hasWiFiPermission = true; 975 } else if (name == "android.permission.CALL_PHONE" || 976 name == "android.permission.CALL_PRIVILEGED" || 977 name == "android.permission.MODIFY_PHONE_STATE" || 978 name == "android.permission.PROCESS_OUTGOING_CALLS" || 979 name == "android.permission.READ_SMS" || 980 name == "android.permission.RECEIVE_SMS" || 981 name == "android.permission.RECEIVE_MMS" || 982 name == "android.permission.RECEIVE_WAP_PUSH" || 983 name == "android.permission.SEND_SMS" || 984 name == "android.permission.WRITE_APN_SETTINGS" || 985 name == "android.permission.WRITE_SMS") { 986 hasTelephonyPermission = true; 987 } 988 printf("uses-permission:'%s'\n", name.string()); 989 } else { 990 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 991 error.string()); 992 goto bail; 993 } 994 } else if (tag == "uses-package") { 995 String8 name = getAttribute(tree, NAME_ATTR, &error); 996 if (name != "" && error == "") { 997 printf("uses-package:'%s'\n", name.string()); 998 } else { 999 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1000 error.string()); 1001 goto bail; 1002 } 1003 } else if (tag == "original-package") { 1004 String8 name = getAttribute(tree, NAME_ATTR, &error); 1005 if (name != "" && error == "") { 1006 printf("original-package:'%s'\n", name.string()); 1007 } else { 1008 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1009 error.string()); 1010 goto bail; 1011 } 1012 } else if (tag == "supports-gl-texture") { 1013 String8 name = getAttribute(tree, NAME_ATTR, &error); 1014 if (name != "" && error == "") { 1015 printf("supports-gl-texture:'%s'\n", name.string()); 1016 } else { 1017 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", 1018 error.string()); 1019 goto bail; 1020 } 1021 } else if (tag == "compatible-screens") { 1022 printCompatibleScreens(tree); 1023 depth--; 1024 } 1025 } else if (depth == 3 && withinApplication) { 1026 withinActivity = false; 1027 withinReceiver = false; 1028 withinService = false; 1029 hasIntentFilter = false; 1030 if(tag == "activity") { 1031 withinActivity = true; 1032 activityName = getAttribute(tree, NAME_ATTR, &error); 1033 if (error != "") { 1034 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); 1035 goto bail; 1036 } 1037 1038 activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); 1039 if (error != "") { 1040 fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string()); 1041 goto bail; 1042 } 1043 1044 activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 1045 if (error != "") { 1046 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); 1047 goto bail; 1048 } 1049 1050 int32_t orien = getResolvedIntegerAttribute(&res, tree, 1051 SCREEN_ORIENTATION_ATTR, &error); 1052 if (error == "") { 1053 if (orien == 0 || orien == 6 || orien == 8) { 1054 // Requests landscape, sensorLandscape, or reverseLandscape. 1055 reqScreenLandscapeFeature = true; 1056 } else if (orien == 1 || orien == 7 || orien == 9) { 1057 // Requests portrait, sensorPortrait, or reversePortrait. 1058 reqScreenPortraitFeature = true; 1059 } 1060 } 1061 } else if (tag == "uses-library") { 1062 String8 libraryName = getAttribute(tree, NAME_ATTR, &error); 1063 if (error != "") { 1064 fprintf(stderr, "ERROR getting 'android:name' attribute for uses-library: %s\n", error.string()); 1065 goto bail; 1066 } 1067 int req = getIntegerAttribute(tree, 1068 REQUIRED_ATTR, NULL, 1); 1069 printf("uses-library%s:'%s'\n", 1070 req ? "" : "-not-required", libraryName.string()); 1071 } else if (tag == "receiver") { 1072 withinReceiver = true; 1073 receiverName = getAttribute(tree, NAME_ATTR, &error); 1074 1075 if (error != "") { 1076 fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string()); 1077 goto bail; 1078 } 1079 } else if (tag == "service") { 1080 withinService = true; 1081 serviceName = getAttribute(tree, NAME_ATTR, &error); 1082 1083 if (error != "") { 1084 fprintf(stderr, "ERROR getting 'android:name' attribute for service: %s\n", error.string()); 1085 goto bail; 1086 } 1087 } 1088 } else if ((depth == 4) && (tag == "intent-filter")) { 1089 hasIntentFilter = true; 1090 withinIntentFilter = true; 1091 actMainActivity = actWidgetReceivers = actImeService = actWallpaperService = false; 1092 } else if ((depth == 5) && withinIntentFilter){ 1093 String8 action; 1094 if (tag == "action") { 1095 action = getAttribute(tree, NAME_ATTR, &error); 1096 if (error != "") { 1097 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); 1098 goto bail; 1099 } 1100 if (withinActivity) { 1101 if (action == "android.intent.action.MAIN") { 1102 isMainActivity = true; 1103 actMainActivity = true; 1104 } 1105 } else if (withinReceiver) { 1106 if (action == "android.appwidget.action.APPWIDGET_UPDATE") { 1107 actWidgetReceivers = true; 1108 } 1109 } else if (withinService) { 1110 if (action == "android.view.InputMethod") { 1111 actImeService = true; 1112 } else if (action == "android.service.wallpaper.WallpaperService") { 1113 actWallpaperService = true; 1114 } 1115 } 1116 if (action == "android.intent.action.SEARCH") { 1117 isSearchable = true; 1118 } 1119 } 1120 1121 if (tag == "category") { 1122 String8 category = getAttribute(tree, NAME_ATTR, &error); 1123 if (error != "") { 1124 fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string()); 1125 goto bail; 1126 } 1127 if (withinActivity) { 1128 if (category == "android.intent.category.LAUNCHER") { 1129 isLauncherActivity = true; 1130 } 1131 } 1132 } 1133 } 1134 } 1135 1136 /* The following blocks handle printing "inferred" uses-features, based 1137 * on whether related features or permissions are used by the app. 1138 * Note that the various spec*Feature variables denote whether the 1139 * relevant tag was *present* in the AndroidManfest, not that it was 1140 * present and set to true. 1141 */ 1142 // Camera-related back-compatibility logic 1143 if (!specCameraFeature) { 1144 if (reqCameraFlashFeature || reqCameraAutofocusFeature) { 1145 // if app requested a sub-feature (autofocus or flash) and didn't 1146 // request the base camera feature, we infer that it meant to 1147 printf("uses-feature:'android.hardware.camera'\n"); 1148 } else if (hasCameraPermission) { 1149 // if app wants to use camera but didn't request the feature, we infer 1150 // that it meant to, and further that it wants autofocus 1151 // (which was the 1.0 - 1.5 behavior) 1152 printf("uses-feature:'android.hardware.camera'\n"); 1153 if (!specCameraAutofocusFeature) { 1154 printf("uses-feature:'android.hardware.camera.autofocus'\n"); 1155 } 1156 } 1157 } 1158 1159 // Location-related back-compatibility logic 1160 if (!specLocationFeature && 1161 (hasMockLocPermission || hasCoarseLocPermission || hasGpsPermission || 1162 hasGeneralLocPermission || reqNetworkLocFeature || reqGpsFeature)) { 1163 // if app either takes a location-related permission or requests one of the 1164 // sub-features, we infer that it also meant to request the base location feature 1165 printf("uses-feature:'android.hardware.location'\n"); 1166 } 1167 if (!specGpsFeature && hasGpsPermission) { 1168 // if app takes GPS (FINE location) perm but does not request the GPS 1169 // feature, we infer that it meant to 1170 printf("uses-feature:'android.hardware.location.gps'\n"); 1171 } 1172 if (!specNetworkLocFeature && hasCoarseLocPermission) { 1173 // if app takes Network location (COARSE location) perm but does not request the 1174 // network location feature, we infer that it meant to 1175 printf("uses-feature:'android.hardware.location.network'\n"); 1176 } 1177 1178 // Bluetooth-related compatibility logic 1179 if (!specBluetoothFeature && hasBluetoothPermission && (targetSdk > 4)) { 1180 // if app takes a Bluetooth permission but does not request the Bluetooth 1181 // feature, we infer that it meant to 1182 printf("uses-feature:'android.hardware.bluetooth'\n"); 1183 } 1184 1185 // Microphone-related compatibility logic 1186 if (!specMicrophoneFeature && hasRecordAudioPermission) { 1187 // if app takes the record-audio permission but does not request the microphone 1188 // feature, we infer that it meant to 1189 printf("uses-feature:'android.hardware.microphone'\n"); 1190 } 1191 1192 // WiFi-related compatibility logic 1193 if (!specWiFiFeature && hasWiFiPermission) { 1194 // if app takes one of the WiFi permissions but does not request the WiFi 1195 // feature, we infer that it meant to 1196 printf("uses-feature:'android.hardware.wifi'\n"); 1197 } 1198 1199 // Telephony-related compatibility logic 1200 if (!specTelephonyFeature && (hasTelephonyPermission || reqTelephonySubFeature)) { 1201 // if app takes one of the telephony permissions or requests a sub-feature but 1202 // does not request the base telephony feature, we infer that it meant to 1203 printf("uses-feature:'android.hardware.telephony'\n"); 1204 } 1205 1206 // Touchscreen-related back-compatibility logic 1207 if (!specTouchscreenFeature) { // not a typo! 1208 // all apps are presumed to require a touchscreen, unless they explicitly say 1209 // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> 1210 // Note that specTouchscreenFeature is true if the tag is present, regardless 1211 // of whether its value is true or false, so this is safe 1212 printf("uses-feature:'android.hardware.touchscreen'\n"); 1213 } 1214 if (!specMultitouchFeature && reqDistinctMultitouchFeature) { 1215 // if app takes one of the telephony permissions or requests a sub-feature but 1216 // does not request the base telephony feature, we infer that it meant to 1217 printf("uses-feature:'android.hardware.touchscreen.multitouch'\n"); 1218 } 1219 1220 // Landscape/portrait-related compatibility logic 1221 if (!specScreenLandscapeFeature && !specScreenPortraitFeature) { 1222 // If the app has specified any activities in its manifest 1223 // that request a specific orientation, then assume that 1224 // orientation is required. 1225 if (reqScreenLandscapeFeature) { 1226 printf("uses-feature:'android.hardware.screen.landscape'\n"); 1227 } 1228 if (reqScreenPortraitFeature) { 1229 printf("uses-feature:'android.hardware.screen.portrait'\n"); 1230 } 1231 } 1232 1233 if (hasMainActivity) { 1234 printf("main\n"); 1235 } 1236 if (hasWidgetReceivers) { 1237 printf("app-widget\n"); 1238 } 1239 if (hasImeService) { 1240 printf("ime\n"); 1241 } 1242 if (hasWallpaperService) { 1243 printf("wallpaper\n"); 1244 } 1245 if (hasOtherActivities) { 1246 printf("other-activities\n"); 1247 } 1248 if (isSearchable) { 1249 printf("search\n"); 1250 } 1251 if (hasOtherReceivers) { 1252 printf("other-receivers\n"); 1253 } 1254 if (hasOtherServices) { 1255 printf("other-services\n"); 1256 } 1257 1258 // For modern apps, if screen size buckets haven't been specified 1259 // but the new width ranges have, then infer the buckets from them. 1260 if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0 1261 && requiresSmallestWidthDp > 0) { 1262 int compatWidth = compatibleWidthLimitDp; 1263 if (compatWidth <= 0) compatWidth = requiresSmallestWidthDp; 1264 if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) { 1265 smallScreen = -1; 1266 } else { 1267 smallScreen = 0; 1268 } 1269 if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) { 1270 normalScreen = -1; 1271 } else { 1272 normalScreen = 0; 1273 } 1274 if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) { 1275 largeScreen = -1; 1276 } else { 1277 largeScreen = 0; 1278 } 1279 if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) { 1280 xlargeScreen = -1; 1281 } else { 1282 xlargeScreen = 0; 1283 } 1284 } 1285 1286 // Determine default values for any unspecified screen sizes, 1287 // based on the target SDK of the package. As of 4 (donut) 1288 // the screen size support was introduced, so all default to 1289 // enabled. 1290 if (smallScreen > 0) { 1291 smallScreen = targetSdk >= 4 ? -1 : 0; 1292 } 1293 if (normalScreen > 0) { 1294 normalScreen = -1; 1295 } 1296 if (largeScreen > 0) { 1297 largeScreen = targetSdk >= 4 ? -1 : 0; 1298 } 1299 if (xlargeScreen > 0) { 1300 // Introduced in Gingerbread. 1301 xlargeScreen = targetSdk >= 9 ? -1 : 0; 1302 } 1303 if (anyDensity > 0) { 1304 anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0 1305 || compatibleWidthLimitDp > 0) ? -1 : 0; 1306 } 1307 printf("supports-screens:"); 1308 if (smallScreen != 0) printf(" 'small'"); 1309 if (normalScreen != 0) printf(" 'normal'"); 1310 if (largeScreen != 0) printf(" 'large'"); 1311 if (xlargeScreen != 0) printf(" 'xlarge'"); 1312 printf("\n"); 1313 printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false"); 1314 if (requiresSmallestWidthDp > 0) { 1315 printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp); 1316 } 1317 if (compatibleWidthLimitDp > 0) { 1318 printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp); 1319 } 1320 if (largestWidthLimitDp > 0) { 1321 printf("largest-width-limit:'%d'\n", largestWidthLimitDp); 1322 } 1323 1324 printf("locales:"); 1325 const size_t NL = locales.size(); 1326 for (size_t i=0; i<NL; i++) { 1327 const char* localeStr = locales[i].string(); 1328 if (localeStr == NULL || strlen(localeStr) == 0) { 1329 localeStr = "--_--"; 1330 } 1331 printf(" '%s'", localeStr); 1332 } 1333 printf("\n"); 1334 1335 printf("densities:"); 1336 const size_t ND = densities.size(); 1337 for (size_t i=0; i<ND; i++) { 1338 printf(" '%d'", densities[i]); 1339 } 1340 printf("\n"); 1341 1342 AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib"); 1343 if (dir != NULL) { 1344 if (dir->getFileCount() > 0) { 1345 printf("native-code:"); 1346 for (size_t i=0; i<dir->getFileCount(); i++) { 1347 printf(" '%s'", dir->getFileName(i).string()); 1348 } 1349 printf("\n"); 1350 } 1351 delete dir; 1352 } 1353 } else if (strcmp("configurations", option) == 0) { 1354 Vector<ResTable_config> configs; 1355 res.getConfigurations(&configs); 1356 const size_t N = configs.size(); 1357 for (size_t i=0; i<N; i++) { 1358 printf("%s\n", configs[i].toString().string()); 1359 } 1360 } else { 1361 fprintf(stderr, "ERROR: unknown dump option '%s'\n", option); 1362 goto bail; 1363 } 1364 } 1365 1366 result = NO_ERROR; 1367 1368bail: 1369 if (asset) { 1370 delete asset; 1371 } 1372 return (result != NO_ERROR); 1373} 1374 1375 1376/* 1377 * Handle the "add" command, which wants to add files to a new or 1378 * pre-existing archive. 1379 */ 1380int doAdd(Bundle* bundle) 1381{ 1382 ZipFile* zip = NULL; 1383 status_t result = UNKNOWN_ERROR; 1384 const char* zipFileName; 1385 1386 if (bundle->getUpdate()) { 1387 /* avoid confusion */ 1388 fprintf(stderr, "ERROR: can't use '-u' with add\n"); 1389 goto bail; 1390 } 1391 1392 if (bundle->getFileSpecCount() < 1) { 1393 fprintf(stderr, "ERROR: must specify zip file name\n"); 1394 goto bail; 1395 } 1396 zipFileName = bundle->getFileSpecEntry(0); 1397 1398 if (bundle->getFileSpecCount() < 2) { 1399 fprintf(stderr, "NOTE: nothing to do\n"); 1400 goto bail; 1401 } 1402 1403 zip = openReadWrite(zipFileName, true); 1404 if (zip == NULL) { 1405 fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName); 1406 goto bail; 1407 } 1408 1409 for (int i = 1; i < bundle->getFileSpecCount(); i++) { 1410 const char* fileName = bundle->getFileSpecEntry(i); 1411 1412 if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) { 1413 printf(" '%s'... (from gzip)\n", fileName); 1414 result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL); 1415 } else { 1416 if (bundle->getJunkPath()) { 1417 String8 storageName = String8(fileName).getPathLeaf(); 1418 printf(" '%s' as '%s'...\n", fileName, storageName.string()); 1419 result = zip->add(fileName, storageName.string(), 1420 bundle->getCompressionMethod(), NULL); 1421 } else { 1422 printf(" '%s'...\n", fileName); 1423 result = zip->add(fileName, bundle->getCompressionMethod(), NULL); 1424 } 1425 } 1426 if (result != NO_ERROR) { 1427 fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName); 1428 if (result == NAME_NOT_FOUND) 1429 fprintf(stderr, ": file not found\n"); 1430 else if (result == ALREADY_EXISTS) 1431 fprintf(stderr, ": already exists in archive\n"); 1432 else 1433 fprintf(stderr, "\n"); 1434 goto bail; 1435 } 1436 } 1437 1438 result = NO_ERROR; 1439 1440bail: 1441 delete zip; 1442 return (result != NO_ERROR); 1443} 1444 1445 1446/* 1447 * Delete files from an existing archive. 1448 */ 1449int doRemove(Bundle* bundle) 1450{ 1451 ZipFile* zip = NULL; 1452 status_t result = UNKNOWN_ERROR; 1453 const char* zipFileName; 1454 1455 if (bundle->getFileSpecCount() < 1) { 1456 fprintf(stderr, "ERROR: must specify zip file name\n"); 1457 goto bail; 1458 } 1459 zipFileName = bundle->getFileSpecEntry(0); 1460 1461 if (bundle->getFileSpecCount() < 2) { 1462 fprintf(stderr, "NOTE: nothing to do\n"); 1463 goto bail; 1464 } 1465 1466 zip = openReadWrite(zipFileName, false); 1467 if (zip == NULL) { 1468 fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n", 1469 zipFileName); 1470 goto bail; 1471 } 1472 1473 for (int i = 1; i < bundle->getFileSpecCount(); i++) { 1474 const char* fileName = bundle->getFileSpecEntry(i); 1475 ZipEntry* entry; 1476 1477 entry = zip->getEntryByName(fileName); 1478 if (entry == NULL) { 1479 printf(" '%s' NOT FOUND\n", fileName); 1480 continue; 1481 } 1482 1483 result = zip->remove(entry); 1484 1485 if (result != NO_ERROR) { 1486 fprintf(stderr, "Unable to delete '%s' from '%s'\n", 1487 bundle->getFileSpecEntry(i), zipFileName); 1488 goto bail; 1489 } 1490 } 1491 1492 /* update the archive */ 1493 zip->flush(); 1494 1495bail: 1496 delete zip; 1497 return (result != NO_ERROR); 1498} 1499 1500 1501/* 1502 * Package up an asset directory and associated application files. 1503 */ 1504int doPackage(Bundle* bundle) 1505{ 1506 const char* outputAPKFile; 1507 int retVal = 1; 1508 status_t err; 1509 sp<AaptAssets> assets; 1510 int N; 1511 FILE* fp; 1512 String8 dependencyFile; 1513 1514 // -c zz_ZZ means do pseudolocalization 1515 ResourceFilter filter; 1516 err = filter.parse(bundle->getConfigurations()); 1517 if (err != NO_ERROR) { 1518 goto bail; 1519 } 1520 if (filter.containsPseudo()) { 1521 bundle->setPseudolocalize(true); 1522 } 1523 1524 N = bundle->getFileSpecCount(); 1525 if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0 1526 && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) { 1527 fprintf(stderr, "ERROR: no input files\n"); 1528 goto bail; 1529 } 1530 1531 outputAPKFile = bundle->getOutputAPKFile(); 1532 1533 // Make sure the filenames provided exist and are of the appropriate type. 1534 if (outputAPKFile) { 1535 FileType type; 1536 type = getFileType(outputAPKFile); 1537 if (type != kFileTypeNonexistent && type != kFileTypeRegular) { 1538 fprintf(stderr, 1539 "ERROR: output file '%s' exists but is not regular file\n", 1540 outputAPKFile); 1541 goto bail; 1542 } 1543 } 1544 1545 // Load the assets. 1546 assets = new AaptAssets(); 1547 1548 // Set up the resource gathering in assets if we're going to generate 1549 // dependency files 1550 if (bundle->getGenDependencies()) { 1551 sp<FilePathStore> resPathStore = new FilePathStore; 1552 assets->setFullResPaths(resPathStore); 1553 sp<FilePathStore> assetPathStore = new FilePathStore; 1554 assets->setFullAssetPaths(assetPathStore); 1555 } 1556 1557 err = assets->slurpFromArgs(bundle); 1558 if (err < 0) { 1559 goto bail; 1560 } 1561 1562 if (bundle->getVerbose()) { 1563 assets->print(); 1564 } 1565 1566 // If they asked for any fileAs that need to be compiled, do so. 1567 if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) { 1568 err = buildResources(bundle, assets); 1569 if (err != 0) { 1570 goto bail; 1571 } 1572 } 1573 1574 // At this point we've read everything and processed everything. From here 1575 // on out it's just writing output files. 1576 if (SourcePos::hasErrors()) { 1577 goto bail; 1578 } 1579 1580 if (bundle->getGenDependencies()) { 1581 if (outputAPKFile) { 1582 dependencyFile = String8(outputAPKFile); 1583 // Strip the extension and add new one 1584 dependencyFile = dependencyFile.getBasePath(); 1585 dependencyFile.append(".d"); 1586 } else { 1587 dependencyFile = String8(bundle->getRClassDir()); 1588 dependencyFile.appendPath("R.d"); 1589 } 1590 // Make sure we have a clean dependency file to start with 1591 fp = fopen(dependencyFile, "w"); 1592 fclose(fp); 1593 } 1594 1595 // Write out R.java constants 1596 if (assets->getPackage() == assets->getSymbolsPrivatePackage()) { 1597 if (bundle->getCustomPackage() == NULL) { 1598 err = writeResourceSymbols(bundle, assets, assets->getPackage(), true); 1599 // Copy R.java for libraries 1600 if (bundle->getExtraPackages() != NULL) { 1601 // Split on colon 1602 String8 libs(bundle->getExtraPackages()); 1603 char* packageString = strtok(libs.lockBuffer(libs.length()), ":"); 1604 while (packageString != NULL) { 1605 err = writeResourceSymbols(bundle, assets, String8(packageString), true); 1606 packageString = strtok(NULL, ":"); 1607 } 1608 libs.unlockBuffer(); 1609 } 1610 } else { 1611 const String8 customPkg(bundle->getCustomPackage()); 1612 err = writeResourceSymbols(bundle, assets, customPkg, true); 1613 } 1614 if (err < 0) { 1615 goto bail; 1616 } 1617 } else { 1618 err = writeResourceSymbols(bundle, assets, assets->getPackage(), false); 1619 if (err < 0) { 1620 goto bail; 1621 } 1622 err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true); 1623 if (err < 0) { 1624 goto bail; 1625 } 1626 } 1627 1628 // Write out the ProGuard file 1629 err = writeProguardFile(bundle, assets); 1630 if (err < 0) { 1631 goto bail; 1632 } 1633 1634 // Write the apk 1635 if (outputAPKFile) { 1636 err = writeAPK(bundle, assets, String8(outputAPKFile)); 1637 if (err != NO_ERROR) { 1638 fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputAPKFile); 1639 goto bail; 1640 } 1641 } 1642 1643 if (bundle->getGenDependencies()) { 1644 // Now that writeResourceSymbols or writeAPK has taken care of writing 1645 // the targets to our dependency file, we'll write the prereqs 1646 fp = fopen(dependencyFile, "a+"); 1647 fprintf(fp, " : "); 1648 bool includeRaw = (outputAPKFile != NULL); 1649 err = writeDependencyPreReqs(bundle, assets, fp, includeRaw); 1650 // Also manually add the AndroidManifeset since it's a non-asset 1651 fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile()); 1652 fclose(fp); 1653 } 1654 1655 retVal = 0; 1656bail: 1657 if (SourcePos::hasErrors()) { 1658 SourcePos::printErrors(stderr); 1659 } 1660 return retVal; 1661} 1662