blob: f6afc8594309a9265b0789c9bd99a46dd9d914e9 [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>
5#include <utils/String8.h>
6
7#include <fcntl.h>
8#include <sys/mman.h>
9#include <sys/stat.h>
10
11using namespace android;
12
Colin Cross13221c92014-02-11 18:04:44 -080013namespace {
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070014 static const uint32_t IDMAP_MAGIC = 0x504D4449;
Colin Cross13221c92014-02-11 18:04:44 -080015 static const size_t PATH_LENGTH = 256;
Colin Cross13221c92014-02-11 18:04:44 -080016
17 void printe(const char *fmt, ...);
18
19 class IdmapBuffer {
20 private:
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070021 const char* buf_;
Colin Cross13221c92014-02-11 18:04:44 -080022 size_t len_;
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070023 size_t pos_;
Colin Cross13221c92014-02-11 18:04:44 -080024 public:
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070025 IdmapBuffer() : buf_((const char *)MAP_FAILED), len_(0), pos_(0) {}
Colin Cross13221c92014-02-11 18:04:44 -080026
27 ~IdmapBuffer() {
28 if (buf_ != MAP_FAILED) {
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070029 munmap(const_cast<char*>(buf_), len_);
Colin Cross13221c92014-02-11 18:04:44 -080030 }
31 }
32
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070033 status_t init(const char *idmap_path) {
Colin Cross13221c92014-02-11 18:04:44 -080034 struct stat st;
35 int fd;
36
37 if (stat(idmap_path, &st) < 0) {
38 printe("failed to stat idmap '%s': %s\n", idmap_path, strerror(errno));
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070039 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080040 }
41 len_ = st.st_size;
42 if ((fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY))) < 0) {
43 printe("failed to open idmap '%s': %s\n", idmap_path, strerror(errno));
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070044 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080045 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070046 if ((buf_ = (const char*)mmap(NULL, len_, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
Colin Cross13221c92014-02-11 18:04:44 -080047 close(fd);
48 printe("failed to mmap idmap: %s\n", strerror(errno));
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070049 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080050 }
51 close(fd);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070052 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080053 }
54
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070055 status_t nextUint32(uint32_t* i) {
Colin Cross13221c92014-02-11 18:04:44 -080056 if (!buf_) {
57 printe("failed to read next uint32_t: buffer not initialized\n");
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070058 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080059 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070060
61 if (pos_ + sizeof(uint32_t) > len_) {
Colin Cross13221c92014-02-11 18:04:44 -080062 printe("failed to read next uint32_t: end of buffer reached at pos=0x%08x\n",
63 pos_);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070064 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080065 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070066
67 if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x3) != 0) {
68 printe("failed to read next uint32_t: not aligned on 4-byte boundary\n");
69 return UNKNOWN_ERROR;
70 }
71
72 *i = dtohl(*reinterpret_cast<const uint32_t*>(buf_ + pos_));
73 pos_ += sizeof(uint32_t);
74 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -080075 }
76
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070077 status_t nextUint16(uint16_t* i) {
78 if (!buf_) {
79 printe("failed to read next uint16_t: buffer not initialized\n");
80 return UNKNOWN_ERROR;
81 }
82
83 if (pos_ + sizeof(uint16_t) > len_) {
84 printe("failed to read next uint16_t: end of buffer reached at pos=0x%08x\n",
85 pos_);
86 return UNKNOWN_ERROR;
87 }
88
89 if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x1) != 0) {
90 printe("failed to read next uint32_t: not aligned on 2-byte boundary\n");
91 return UNKNOWN_ERROR;
92 }
93
94 *i = dtohs(*reinterpret_cast<const uint16_t*>(buf_ + pos_));
95 pos_ += sizeof(uint16_t);
96 return NO_ERROR;
97 }
98
99 status_t nextPath(char *b) {
Colin Cross13221c92014-02-11 18:04:44 -0800100 if (!buf_) {
101 printe("failed to read next path: buffer not initialized\n");
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700102 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800103 }
104 if (pos_ + PATH_LENGTH > len_) {
105 printe("failed to read next path: end of buffer reached at pos=0x%08x\n", pos_);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700106 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800107 }
108 memcpy(b, buf_ + pos_, PATH_LENGTH);
Colin Cross13221c92014-02-11 18:04:44 -0800109 pos_ += PATH_LENGTH;
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700110 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800111 }
112 };
113
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700114 void printe(const char *fmt, ...) {
Colin Cross13221c92014-02-11 18:04:44 -0800115 va_list ap;
116
117 va_start(ap, fmt);
118 fprintf(stderr, "error: ");
119 vfprintf(stderr, fmt, ap);
120 va_end(ap);
121 }
122
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700123 void print_header() {
124 printf("SECTION ENTRY VALUE COMMENT\n");
Colin Cross13221c92014-02-11 18:04:44 -0800125 }
126
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700127 void print(const char *section, const char *subsection, uint32_t value, const char *fmt, ...) {
Colin Cross13221c92014-02-11 18:04:44 -0800128 va_list ap;
129
130 va_start(ap, fmt);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700131 printf("%-12s %-12s 0x%08x ", section, subsection, value);
Colin Cross13221c92014-02-11 18:04:44 -0800132 vprintf(fmt, ap);
133 printf("\n");
134 va_end(ap);
135 }
136
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700137 void print_path(const char *section, const char *subsection, const char *fmt, ...) {
Colin Cross13221c92014-02-11 18:04:44 -0800138 va_list ap;
139
140 va_start(ap, fmt);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700141 printf("%-12s %-12s .......... ", section, subsection);
Colin Cross13221c92014-02-11 18:04:44 -0800142 vprintf(fmt, ap);
143 printf("\n");
144 va_end(ap);
145 }
146
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700147 status_t resource_metadata(const AssetManager& am, uint32_t res_id,
148 String8 *package, String8 *type, String8 *name) {
Colin Cross13221c92014-02-11 18:04:44 -0800149 const ResTable& rt = am.getResources();
150 struct ResTable::resource_name data;
151 if (!rt.getResourceName(res_id, false, &data)) {
152 printe("failed to get resource name id=0x%08x\n", res_id);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700153 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800154 }
Andreas Gampecfedceb2014-09-30 21:48:18 -0700155 if (package != NULL) {
Colin Cross13221c92014-02-11 18:04:44 -0800156 *package = String8(String16(data.package, data.packageLen));
157 }
Andreas Gampecfedceb2014-09-30 21:48:18 -0700158 if (type != NULL) {
Colin Cross13221c92014-02-11 18:04:44 -0800159 *type = String8(String16(data.type, data.typeLen));
160 }
Andreas Gampecfedceb2014-09-30 21:48:18 -0700161 if (name != NULL) {
Colin Cross13221c92014-02-11 18:04:44 -0800162 *name = String8(String16(data.name, data.nameLen));
163 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700164 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800165 }
166
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700167 status_t parse_idmap_header(IdmapBuffer& buf, AssetManager& am) {
168 uint32_t i;
Colin Cross13221c92014-02-11 18:04:44 -0800169 char path[PATH_LENGTH];
170
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700171 status_t err = buf.nextUint32(&i);
172 if (err != NO_ERROR) {
173 return err;
174 }
175
Colin Cross13221c92014-02-11 18:04:44 -0800176 if (i != IDMAP_MAGIC) {
177 printe("not an idmap file: actual magic constant 0x%08x does not match expected magic "
178 "constant 0x%08x\n", i, IDMAP_MAGIC);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700179 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800180 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700181
Colin Cross13221c92014-02-11 18:04:44 -0800182 print_header();
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700183 print("IDMAP HEADER", "magic", i, "");
Colin Cross13221c92014-02-11 18:04:44 -0800184
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700185 err = buf.nextUint32(&i);
186 if (err != NO_ERROR) {
187 return err;
Colin Cross13221c92014-02-11 18:04:44 -0800188 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700189 print("", "version", i, "");
190
191 err = buf.nextUint32(&i);
192 if (err != NO_ERROR) {
193 return err;
194 }
195 print("", "base crc", i, "");
196
197 err = buf.nextUint32(&i);
198 if (err != NO_ERROR) {
199 return err;
200 }
201 print("", "overlay crc", i, "");
202
203 err = buf.nextPath(path);
204 if (err != NO_ERROR) {
205 // printe done from IdmapBuffer::nextPath
206 return err;
207 }
208 print_path("", "base path", "%s", path);
209
Colin Cross13221c92014-02-11 18:04:44 -0800210 if (!am.addAssetPath(String8(path), NULL)) {
211 printe("failed to add '%s' as asset path\n", path);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700212 return UNKNOWN_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800213 }
214
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700215 err = buf.nextPath(path);
216 if (err != NO_ERROR) {
Colin Cross13221c92014-02-11 18:04:44 -0800217 // printe done from IdmapBuffer::nextPath
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700218 return err;
Colin Cross13221c92014-02-11 18:04:44 -0800219 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700220 print_path("", "overlay path", "%s", path);
Colin Cross13221c92014-02-11 18:04:44 -0800221
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700222 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800223 }
224
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700225 status_t parse_data(IdmapBuffer& buf, const AssetManager& am) {
226 const uint32_t packageId = am.getResources().getBasePackageId(0);
Colin Cross13221c92014-02-11 18:04:44 -0800227
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700228 uint16_t data16;
229 status_t err = buf.nextUint16(&data16);
230 if (err != NO_ERROR) {
231 return err;
232 }
233 print("DATA HEADER", "target pkg", static_cast<uint32_t>(data16), "");
Colin Cross13221c92014-02-11 18:04:44 -0800234
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700235 err = buf.nextUint16(&data16);
236 if (err != NO_ERROR) {
237 return err;
238 }
239 print("", "types count", static_cast<uint32_t>(data16), "");
240
241 uint32_t typeCount = static_cast<uint32_t>(data16);
242 while (typeCount > 0) {
243 typeCount--;
244
245 err = buf.nextUint16(&data16);
246 if (err != NO_ERROR) {
247 return err;
248 }
249 const uint32_t targetTypeId = static_cast<uint32_t>(data16);
250 print("DATA BLOCK", "target type", targetTypeId, "");
251
252 err = buf.nextUint16(&data16);
253 if (err != NO_ERROR) {
254 return err;
255 }
256 print("", "overlay type", static_cast<uint32_t>(data16), "");
257
258 err = buf.nextUint16(&data16);
259 if (err != NO_ERROR) {
260 return err;
261 }
262 const uint32_t entryCount = static_cast<uint32_t>(data16);
263 print("", "entry count", entryCount, "");
264
265 err = buf.nextUint16(&data16);
266 if (err != NO_ERROR) {
267 return err;
268 }
269 const uint32_t entryOffset = static_cast<uint32_t>(data16);
270 print("", "entry offset", entryOffset, "");
271
272 for (uint32_t i = 0; i < entryCount; i++) {
273 uint32_t data32;
274 err = buf.nextUint32(&data32);
275 if (err != NO_ERROR) {
276 return err;
277 }
278
279 uint32_t resID = (packageId << 24) | (targetTypeId << 16) | (entryOffset + i);
Colin Cross13221c92014-02-11 18:04:44 -0800280 String8 type;
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700281 String8 name;
282 err = resource_metadata(am, resID, NULL, &type, &name);
283 if (err != NO_ERROR) {
284 return err;
Colin Cross13221c92014-02-11 18:04:44 -0800285 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700286 print("", "entry", data32, "%s/%s", type.string(), name.string());
Colin Cross13221c92014-02-11 18:04:44 -0800287 }
288 }
289
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700290 return NO_ERROR;
Colin Cross13221c92014-02-11 18:04:44 -0800291 }
292}
293
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700294int idmap_inspect(const char *idmap_path) {
Colin Cross13221c92014-02-11 18:04:44 -0800295 IdmapBuffer buf;
296 if (buf.init(idmap_path) < 0) {
297 // printe done from IdmapBuffer::init
298 return EXIT_FAILURE;
299 }
300 AssetManager am;
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700301 if (parse_idmap_header(buf, am) != NO_ERROR) {
Colin Cross13221c92014-02-11 18:04:44 -0800302 // printe done from parse_idmap_header
303 return EXIT_FAILURE;
304 }
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700305 if (parse_data(buf, am) != NO_ERROR) {
Colin Cross13221c92014-02-11 18:04:44 -0800306 // printe done from parse_data_header
307 return EXIT_FAILURE;
308 }
Colin Cross13221c92014-02-11 18:04:44 -0800309 return EXIT_SUCCESS;
310}