inspect.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. #include "idmap.h"
  2. #include <androidfw/AssetManager.h>
  3. #include <androidfw/ResourceTypes.h>
  4. #include <utils/ByteOrder.h>
  5. #include <utils/String8.h>
  6. #include <fcntl.h>
  7. #include <sys/mman.h>
  8. #include <sys/stat.h>
  9. using namespace android;
  10. namespace {
  11. static const uint32_t IDMAP_MAGIC = 0x504D4449;
  12. static const size_t PATH_LENGTH = 256;
  13. void printe(const char *fmt, ...);
  14. class IdmapBuffer {
  15. private:
  16. const char* buf_;
  17. size_t len_;
  18. size_t pos_;
  19. public:
  20. IdmapBuffer() : buf_((const char *)MAP_FAILED), len_(0), pos_(0) {}
  21. ~IdmapBuffer() {
  22. if (buf_ != MAP_FAILED) {
  23. munmap(const_cast<char*>(buf_), len_);
  24. }
  25. }
  26. status_t init(const char *idmap_path) {
  27. struct stat st;
  28. int fd;
  29. if (stat(idmap_path, &st) < 0) {
  30. printe("failed to stat idmap '%s': %s\n", idmap_path, strerror(errno));
  31. return UNKNOWN_ERROR;
  32. }
  33. len_ = st.st_size;
  34. if ((fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY))) < 0) {
  35. printe("failed to open idmap '%s': %s\n", idmap_path, strerror(errno));
  36. return UNKNOWN_ERROR;
  37. }
  38. if ((buf_ = (const char*)mmap(NULL, len_, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
  39. close(fd);
  40. printe("failed to mmap idmap: %s\n", strerror(errno));
  41. return UNKNOWN_ERROR;
  42. }
  43. close(fd);
  44. return NO_ERROR;
  45. }
  46. status_t nextUint32(uint32_t* i) {
  47. if (!buf_) {
  48. printe("failed to read next uint32_t: buffer not initialized\n");
  49. return UNKNOWN_ERROR;
  50. }
  51. if (pos_ + sizeof(uint32_t) > len_) {
  52. printe("failed to read next uint32_t: end of buffer reached at pos=0x%08x\n",
  53. pos_);
  54. return UNKNOWN_ERROR;
  55. }
  56. if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x3) != 0) {
  57. printe("failed to read next uint32_t: not aligned on 4-byte boundary\n");
  58. return UNKNOWN_ERROR;
  59. }
  60. *i = dtohl(*reinterpret_cast<const uint32_t*>(buf_ + pos_));
  61. pos_ += sizeof(uint32_t);
  62. return NO_ERROR;
  63. }
  64. status_t nextUint16(uint16_t* i) {
  65. if (!buf_) {
  66. printe("failed to read next uint16_t: buffer not initialized\n");
  67. return UNKNOWN_ERROR;
  68. }
  69. if (pos_ + sizeof(uint16_t) > len_) {
  70. printe("failed to read next uint16_t: end of buffer reached at pos=0x%08x\n",
  71. pos_);
  72. return UNKNOWN_ERROR;
  73. }
  74. if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x1) != 0) {
  75. printe("failed to read next uint32_t: not aligned on 2-byte boundary\n");
  76. return UNKNOWN_ERROR;
  77. }
  78. *i = dtohs(*reinterpret_cast<const uint16_t*>(buf_ + pos_));
  79. pos_ += sizeof(uint16_t);
  80. return NO_ERROR;
  81. }
  82. status_t nextPath(char *b) {
  83. if (!buf_) {
  84. printe("failed to read next path: buffer not initialized\n");
  85. return UNKNOWN_ERROR;
  86. }
  87. if (pos_ + PATH_LENGTH > len_) {
  88. printe("failed to read next path: end of buffer reached at pos=0x%08x\n", pos_);
  89. return UNKNOWN_ERROR;
  90. }
  91. memcpy(b, buf_ + pos_, PATH_LENGTH);
  92. pos_ += PATH_LENGTH;
  93. return NO_ERROR;
  94. }
  95. };
  96. void printe(const char *fmt, ...) {
  97. va_list ap;
  98. va_start(ap, fmt);
  99. fprintf(stderr, "error: ");
  100. vfprintf(stderr, fmt, ap);
  101. va_end(ap);
  102. }
  103. void print_header() {
  104. printf("SECTION ENTRY VALUE COMMENT\n");
  105. }
  106. void print(const char *section, const char *subsection, uint32_t value, const char *fmt, ...) {
  107. va_list ap;
  108. va_start(ap, fmt);
  109. printf("%-12s %-12s 0x%08x ", section, subsection, value);
  110. vprintf(fmt, ap);
  111. printf("\n");
  112. va_end(ap);
  113. }
  114. void print_path(const char *section, const char *subsection, const char *fmt, ...) {
  115. va_list ap;
  116. va_start(ap, fmt);
  117. printf("%-12s %-12s .......... ", section, subsection);
  118. vprintf(fmt, ap);
  119. printf("\n");
  120. va_end(ap);
  121. }
  122. status_t resource_metadata(const AssetManager& am, uint32_t res_id,
  123. String8 *package, String8 *type, String8 *name) {
  124. const ResTable& rt = am.getResources();
  125. struct ResTable::resource_name data;
  126. if (!rt.getResourceName(res_id, false, &data)) {
  127. printe("failed to get resource name id=0x%08x\n", res_id);
  128. return UNKNOWN_ERROR;
  129. }
  130. if (package != NULL) {
  131. *package = String8(String16(data.package, data.packageLen));
  132. }
  133. if (type != NULL) {
  134. *type = String8(String16(data.type, data.typeLen));
  135. }
  136. if (name != NULL) {
  137. *name = String8(String16(data.name, data.nameLen));
  138. }
  139. return NO_ERROR;
  140. }
  141. status_t parse_idmap_header(IdmapBuffer& buf, AssetManager& am) {
  142. uint32_t i;
  143. char path[PATH_LENGTH];
  144. status_t err = buf.nextUint32(&i);
  145. if (err != NO_ERROR) {
  146. return err;
  147. }
  148. if (i != IDMAP_MAGIC) {
  149. printe("not an idmap file: actual magic constant 0x%08x does not match expected magic "
  150. "constant 0x%08x\n", i, IDMAP_MAGIC);
  151. return UNKNOWN_ERROR;
  152. }
  153. print_header();
  154. print("IDMAP HEADER", "magic", i, "");
  155. err = buf.nextUint32(&i);
  156. if (err != NO_ERROR) {
  157. return err;
  158. }
  159. print("", "version", i, "");
  160. err = buf.nextUint32(&i);
  161. if (err != NO_ERROR) {
  162. return err;
  163. }
  164. print("", "base crc", i, "");
  165. err = buf.nextUint32(&i);
  166. if (err != NO_ERROR) {
  167. return err;
  168. }
  169. print("", "overlay crc", i, "");
  170. err = buf.nextPath(path);
  171. if (err != NO_ERROR) {
  172. // printe done from IdmapBuffer::nextPath
  173. return err;
  174. }
  175. print_path("", "base path", "%s", path);
  176. if (!am.addAssetPath(String8(path), NULL)) {
  177. printe("failed to add '%s' as asset path\n", path);
  178. return UNKNOWN_ERROR;
  179. }
  180. err = buf.nextPath(path);
  181. if (err != NO_ERROR) {
  182. // printe done from IdmapBuffer::nextPath
  183. return err;
  184. }
  185. print_path("", "overlay path", "%s", path);
  186. return NO_ERROR;
  187. }
  188. status_t parse_data(IdmapBuffer& buf, const AssetManager& am) {
  189. const uint32_t packageId = am.getResources().getBasePackageId(0);
  190. uint16_t data16;
  191. status_t err = buf.nextUint16(&data16);
  192. if (err != NO_ERROR) {
  193. return err;
  194. }
  195. print("DATA HEADER", "target pkg", static_cast<uint32_t>(data16), "");
  196. err = buf.nextUint16(&data16);
  197. if (err != NO_ERROR) {
  198. return err;
  199. }
  200. print("", "types count", static_cast<uint32_t>(data16), "");
  201. uint32_t typeCount = static_cast<uint32_t>(data16);
  202. while (typeCount > 0) {
  203. typeCount--;
  204. err = buf.nextUint16(&data16);
  205. if (err != NO_ERROR) {
  206. return err;
  207. }
  208. const uint32_t targetTypeId = static_cast<uint32_t>(data16);
  209. print("DATA BLOCK", "target type", targetTypeId, "");
  210. err = buf.nextUint16(&data16);
  211. if (err != NO_ERROR) {
  212. return err;
  213. }
  214. print("", "overlay type", static_cast<uint32_t>(data16), "");
  215. err = buf.nextUint16(&data16);
  216. if (err != NO_ERROR) {
  217. return err;
  218. }
  219. const uint32_t entryCount = static_cast<uint32_t>(data16);
  220. print("", "entry count", entryCount, "");
  221. err = buf.nextUint16(&data16);
  222. if (err != NO_ERROR) {
  223. return err;
  224. }
  225. const uint32_t entryOffset = static_cast<uint32_t>(data16);
  226. print("", "entry offset", entryOffset, "");
  227. for (uint32_t i = 0; i < entryCount; i++) {
  228. uint32_t data32;
  229. err = buf.nextUint32(&data32);
  230. if (err != NO_ERROR) {
  231. return err;
  232. }
  233. uint32_t resID = (packageId << 24) | (targetTypeId << 16) | (entryOffset + i);
  234. String8 type;
  235. String8 name;
  236. err = resource_metadata(am, resID, NULL, &type, &name);
  237. if (err != NO_ERROR) {
  238. return err;
  239. }
  240. if (data32 != ResTable_type::NO_ENTRY) {
  241. print("", "entry", data32, "%s/%s", type.string(), name.string());
  242. }
  243. }
  244. }
  245. return NO_ERROR;
  246. }
  247. }
  248. int idmap_inspect(const char *idmap_path) {
  249. IdmapBuffer buf;
  250. if (buf.init(idmap_path) < 0) {
  251. // printe done from IdmapBuffer::init
  252. return EXIT_FAILURE;
  253. }
  254. AssetManager am;
  255. if (parse_idmap_header(buf, am) != NO_ERROR) {
  256. // printe done from parse_idmap_header
  257. return EXIT_FAILURE;
  258. }
  259. if (parse_data(buf, am) != NO_ERROR) {
  260. // printe done from parse_data_header
  261. return EXIT_FAILURE;
  262. }
  263. return EXIT_SUCCESS;
  264. }