blob: 20005e2766d8bc32c24f57da73fe39feb4e2511a [file] [log] [blame]
Colin Cross13221c92014-02-11 18:04:44 -08001#include "idmap.h"
2
3#include <androidfw/AssetManager.h>
4#include <androidfw/ResourceTypes.h>
Adam Lesinskice5e56e2016-10-21 17:56:45 -07005#include <utils/ByteOrder.h>
Colin Cross13221c92014-02-11 18:04:44 -08006#include <utils/String8.h>
7
8#include <fcntl.h>
9#include <sys/mman.h>
10#include <sys/stat.h>
11
12using namespace android;
13
Colin Cross13221c92014-02-11 18:04:44 -080014namespace {
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070015 static const uint32_t IDMAP_MAGIC = 0x504D4449;
Colin Cross13221c92014-02-11 18:04:44 -080016 static const size_t PATH_LENGTH = 256;
Colin Cross13221c92014-02-11 18:04:44 -080017
18 void printe(const char *fmt, ...);
19
20 class IdmapBuffer {
21 private:
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070022 const char* buf_;
Colin Cross13221c92014-02-11 18:04:44 -080023 size_t len_;
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070024 size_t pos_;
Colin Cross13221c92014-02-11 18:04:44 -080025 public:
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070026 IdmapBuffer() : buf_((const char *)MAP_FAILED), len_(0), pos_(0) {}
Colin Cross13221c92014-02-11 18:04:44 -080027
28 ~IdmapBuffer() {
29 if (buf_ != MAP_FAILED) {
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070030 munmap(const_cast<char*>(buf_), len_);
Colin Cross13221c92014-02-11 18:04:44 -080031 }
32 }
33
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070034 status_t init(const char *idmap_path) {
Colin Cross13221c92014-02-11 18:04:44 -080035 struct stat st;
36 int fd;
37
38 if (stat(idmap_path, &st) < 0) {
39 printe("failed to stat idmap '%s': %s\n", idmap_path, strerror(errno));
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070040 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080041 }
42 len_ = st.st_size;
43 if ((fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY))) < 0) {
44 printe("failed to open idmap '%s': %s\n", idmap_path, strerror(errno));
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070045 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080046 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070047 if ((buf_ = (const char*)mmap(NULL, len_, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
Colin Cross13221c92014-02-11 18:04:44 -080048 close(fd);
49 printe("failed to mmap idmap: %s\n", strerror(errno));
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070050 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080051 }
52 close(fd);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070053 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080054 }
55
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070056 status_t nextUint32(uint32_t* i) {
Colin Cross13221c92014-02-11 18:04:44 -080057 if (!buf_) {
58 printe("failed to read next uint32_t: buffer not initialized\n");
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070059 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080060 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070061
62 if (pos_ + sizeof(uint32_t) > len_) {
Colin Cross13221c92014-02-11 18:04:44 -080063 printe("failed to read next uint32_t: end of buffer reached at pos=0x%08x\n",
64 pos_);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070065 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080066 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070067
68 if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x3) != 0) {
69 printe("failed to read next uint32_t: not aligned on 4-byte boundary\n");
70 return UNKNOWN_ERROR;
71 }
72
73 *i = dtohl(*reinterpret_cast<const uint32_t*>(buf_ + pos_));
74 pos_ += sizeof(uint32_t);
75 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080076 }
77
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070078 status_t nextUint16(uint16_t* i) {
79 if (!buf_) {
80 printe("failed to read next uint16_t: buffer not initialized\n");
81 return UNKNOWN_ERROR;
82 }
83
84 if (pos_ + sizeof(uint16_t) > len_) {
85 printe("failed to read next uint16_t: end of buffer reached at pos=0x%08x\n",
86 pos_);
87 return UNKNOWN_ERROR;
88 }
89
90 if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x1) != 0) {
91 printe("failed to read next uint32_t: not aligned on 2-byte boundary\n");
92 return UNKNOWN_ERROR;
93 }
94
95 *i = dtohs(*reinterpret_cast<const uint16_t*>(buf_ + pos_));
96 pos_ += sizeof(uint16_t);
97 return NO_ERROR;
98 }
99
100 status_t nextPath(char *b) {
Colin Cross13221c92014-02-11 18:04:44 -0800101 if (!buf_) {
102 printe("failed to read next path: buffer not initialized\n");
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700103 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800104 }
105 if (pos_ + PATH_LENGTH > len_) {
106 printe("failed to read next path: end of buffer reached at pos=0x%08x\n", pos_);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700107 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800108 }
109 memcpy(b, buf_ + pos_, PATH_LENGTH);
Colin Cross13221c92014-02-11 18:04:44 -0800110 pos_ += PATH_LENGTH;
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700111 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800112 }
113 };
114
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700115 void printe(const char *fmt, ...) {
Colin Cross13221c92014-02-11 18:04:44 -0800116 va_list ap;
117
118 va_start(ap, fmt);
119 fprintf(stderr, "error: ");
120 vfprintf(stderr, fmt, ap);
121 va_end(ap);
122 }
123
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700124 void print_header() {
125 printf("SECTION ENTRY VALUE COMMENT\n");
Colin Cross13221c92014-02-11 18:04:44 -0800126 }
127
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700128 void print(const char *section, const char *subsection, uint32_t value, const char *fmt, ...) {
Colin Cross13221c92014-02-11 18:04:44 -0800129 va_list ap;
130
131 va_start(ap, fmt);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700132 printf("%-12s %-12s 0x%08x ", section, subsection, value);
Colin Cross13221c92014-02-11 18:04:44 -0800133 vprintf(fmt, ap);
134 printf("\n");
135 va_end(ap);
136 }
137
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700138 void print_path(const char *section, const char *subsection, const char *fmt, ...) {
Colin Cross13221c92014-02-11 18:04:44 -0800139 va_list ap;
140
141 va_start(ap, fmt);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700142 printf("%-12s %-12s .......... ", section, subsection);
Colin Cross13221c92014-02-11 18:04:44 -0800143 vprintf(fmt, ap);
144 printf("\n");
145 va_end(ap);
146 }
147
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700148 status_t resource_metadata(const AssetManager& am, uint32_t res_id,
149 String8 *package, String8 *type, String8 *name) {
Colin Cross13221c92014-02-11 18:04:44 -0800150 const ResTable& rt = am.getResources();
151 struct ResTable::resource_name data;
152 if (!rt.getResourceName(res_id, false, &data)) {
153 printe("failed to get resource name id=0x%08x\n", res_id);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700154 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800155 }
Andreas Gampecfedceb2014-09-30 21:48:18 -0700156 if (package != NULL) {
Colin Cross13221c92014-02-11 18:04:44 -0800157 *package = String8(String16(data.package, data.packageLen));
158 }
Andreas Gampecfedceb2014-09-30 21:48:18 -0700159 if (type != NULL) {
Colin Cross13221c92014-02-11 18:04:44 -0800160 *type = String8(String16(data.type, data.typeLen));
161 }
Andreas Gampecfedceb2014-09-30 21:48:18 -0700162 if (name != NULL) {
Colin Cross13221c92014-02-11 18:04:44 -0800163 *name = String8(String16(data.name, data.nameLen));
164 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700165 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800166 }
167
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700168 status_t parse_idmap_header(IdmapBuffer& buf, AssetManager& am) {
169 uint32_t i;
Colin Cross13221c92014-02-11 18:04:44 -0800170 char path[PATH_LENGTH];
171
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700172 status_t err = buf.nextUint32(&i);
173 if (err != NO_ERROR) {
174 return err;
175 }
176
Colin Cross13221c92014-02-11 18:04:44 -0800177 if (i != IDMAP_MAGIC) {
178 printe("not an idmap file: actual magic constant 0x%08x does not match expected magic "
179 "constant 0x%08x\n", i, IDMAP_MAGIC);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700180 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800181 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700182
Colin Cross13221c92014-02-11 18:04:44 -0800183 print_header();
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700184 print("IDMAP HEADER", "magic", i, "");
Colin Cross13221c92014-02-11 18:04:44 -0800185
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700186 err = buf.nextUint32(&i);
187 if (err != NO_ERROR) {
188 return err;
Colin Cross13221c92014-02-11 18:04:44 -0800189 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700190 print("", "version", i, "");
191
192 err = buf.nextUint32(&i);
193 if (err != NO_ERROR) {
194 return err;
195 }
196 print("", "base crc", i, "");
197
198 err = buf.nextUint32(&i);
199 if (err != NO_ERROR) {
200 return err;
201 }
202 print("", "overlay crc", i, "");
203
204 err = buf.nextPath(path);
205 if (err != NO_ERROR) {
206 // printe done from IdmapBuffer::nextPath
207 return err;
208 }
209 print_path("", "base path", "%s", path);
210
Colin Cross13221c92014-02-11 18:04:44 -0800211 if (!am.addAssetPath(String8(path), NULL)) {
212 printe("failed to add '%s' as asset path\n", path);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700213 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800214 }
215
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700216 err = buf.nextPath(path);
217 if (err != NO_ERROR) {
Colin Cross13221c92014-02-11 18:04:44 -0800218 // printe done from IdmapBuffer::nextPath
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700219 return err;
Colin Cross13221c92014-02-11 18:04:44 -0800220 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700221 print_path("", "overlay path", "%s", path);
Colin Cross13221c92014-02-11 18:04:44 -0800222
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700223 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800224 }
225
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700226 status_t parse_data(IdmapBuffer& buf, const AssetManager& am) {
227 const uint32_t packageId = am.getResources().getBasePackageId(0);
Colin Cross13221c92014-02-11 18:04:44 -0800228
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700229 uint16_t data16;
230 status_t err = buf.nextUint16(&data16);
231 if (err != NO_ERROR) {
232 return err;
233 }
234 print("DATA HEADER", "target pkg", static_cast<uint32_t>(data16), "");
Colin Cross13221c92014-02-11 18:04:44 -0800235
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700236 err = buf.nextUint16(&data16);
237 if (err != NO_ERROR) {
238 return err;
239 }
240 print("", "types count", static_cast<uint32_t>(data16), "");
241
242 uint32_t typeCount = static_cast<uint32_t>(data16);
243 while (typeCount > 0) {
244 typeCount--;
245
246 err = buf.nextUint16(&data16);
247 if (err != NO_ERROR) {
248 return err;
249 }
250 const uint32_t targetTypeId = static_cast<uint32_t>(data16);
251 print("DATA BLOCK", "target type", targetTypeId, "");
252
253 err = buf.nextUint16(&data16);
254 if (err != NO_ERROR) {
255 return err;
256 }
257 print("", "overlay type", static_cast<uint32_t>(data16), "");
258
259 err = buf.nextUint16(&data16);
260 if (err != NO_ERROR) {
261 return err;
262 }
263 const uint32_t entryCount = static_cast<uint32_t>(data16);
264 print("", "entry count", entryCount, "");
265
266 err = buf.nextUint16(&data16);
267 if (err != NO_ERROR) {
268 return err;
269 }
270 const uint32_t entryOffset = static_cast<uint32_t>(data16);
271 print("", "entry offset", entryOffset, "");
272
273 for (uint32_t i = 0; i < entryCount; i++) {
274 uint32_t data32;
275 err = buf.nextUint32(&data32);
276 if (err != NO_ERROR) {
277 return err;
278 }
279
280 uint32_t resID = (packageId << 24) | (targetTypeId << 16) | (entryOffset + i);
Colin Cross13221c92014-02-11 18:04:44 -0800281 String8 type;
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700282 String8 name;
283 err = resource_metadata(am, resID, NULL, &type, &name);
284 if (err != NO_ERROR) {
285 return err;
Colin Cross13221c92014-02-11 18:04:44 -0800286 }
MÃ¥rten Kongstadea2a1b92016-02-29 14:12:35 +0100287 if (data32 != ResTable_type::NO_ENTRY) {
288 print("", "entry", data32, "%s/%s", type.string(), name.string());
289 }
Colin Cross13221c92014-02-11 18:04:44 -0800290 }
291 }
292
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700293 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800294 }
295}
296
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700297int idmap_inspect(const char *idmap_path) {
Colin Cross13221c92014-02-11 18:04:44 -0800298 IdmapBuffer buf;
299 if (buf.init(idmap_path) < 0) {
300 // printe done from IdmapBuffer::init
301 return EXIT_FAILURE;
302 }
303 AssetManager am;
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700304 if (parse_idmap_header(buf, am) != NO_ERROR) {
Colin Cross13221c92014-02-11 18:04:44 -0800305 // printe done from parse_idmap_header
306 return EXIT_FAILURE;
307 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700308 if (parse_data(buf, am) != NO_ERROR) {
Colin Cross13221c92014-02-11 18:04:44 -0800309 // printe done from parse_data_header
310 return EXIT_FAILURE;
311 }
Colin Cross13221c92014-02-11 18:04:44 -0800312 return EXIT_SUCCESS;
313}