1 #include "idmap.h"
2
3 #include <androidfw/AssetManager.h>
4 #include <androidfw/ResourceTypes.h>
5 #include <utils/ByteOrder.h>
6 #include <utils/String8.h>
7
8 #include <fcntl.h>
9 #include <sys/mman.h>
10 #include <sys/stat.h>
11
12 using namespace android;
13
14 namespace {
15 static const uint32_t IDMAP_MAGIC = 0x504D4449;
16 static const size_t PATH_LENGTH = 256;
17
18 void printe(const char *fmt, ...);
19
20 class IdmapBuffer {
21 private:
22 const char* buf_;
23 size_t len_;
24 size_t pos_;
25 public:
IdmapBuffer()26 IdmapBuffer() : buf_((const char *)MAP_FAILED), len_(0), pos_(0) {}
27
~IdmapBuffer()28 ~IdmapBuffer() {
29 if (buf_ != MAP_FAILED) {
30 munmap(const_cast<char*>(buf_), len_);
31 }
32 }
33
init(const char * idmap_path)34 status_t init(const char *idmap_path) {
35 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));
40 return UNKNOWN_ERROR;
41 }
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));
45 return UNKNOWN_ERROR;
46 }
47 if ((buf_ = (const char*)mmap(NULL, len_, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
48 close(fd);
49 printe("failed to mmap idmap: %s\n", strerror(errno));
50 return UNKNOWN_ERROR;
51 }
52 close(fd);
53 return NO_ERROR;
54 }
55
nextUint32(uint32_t * i)56 status_t nextUint32(uint32_t* i) {
57 if (!buf_) {
58 printe("failed to read next uint32_t: buffer not initialized\n");
59 return UNKNOWN_ERROR;
60 }
61
62 if (pos_ + sizeof(uint32_t) > len_) {
63 printe("failed to read next uint32_t: end of buffer reached at pos=0x%08x\n",
64 pos_);
65 return UNKNOWN_ERROR;
66 }
67
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;
76 }
77
nextUint16(uint16_t * i)78 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
nextPath(char * b)100 status_t nextPath(char *b) {
101 if (!buf_) {
102 printe("failed to read next path: buffer not initialized\n");
103 return UNKNOWN_ERROR;
104 }
105 if (pos_ + PATH_LENGTH > len_) {
106 printe("failed to read next path: end of buffer reached at pos=0x%08x\n", pos_);
107 return UNKNOWN_ERROR;
108 }
109 memcpy(b, buf_ + pos_, PATH_LENGTH);
110 pos_ += PATH_LENGTH;
111 return NO_ERROR;
112 }
113 };
114
printe(const char * fmt,...)115 void printe(const char *fmt, ...) {
116 va_list ap;
117
118 va_start(ap, fmt);
119 fprintf(stderr, "error: ");
120 vfprintf(stderr, fmt, ap);
121 va_end(ap);
122 }
123
print_header()124 void print_header() {
125 printf("SECTION ENTRY VALUE COMMENT\n");
126 }
127
print(const char * section,const char * subsection,uint32_t value,const char * fmt,...)128 void print(const char *section, const char *subsection, uint32_t value, const char *fmt, ...) {
129 va_list ap;
130
131 va_start(ap, fmt);
132 printf("%-12s %-12s 0x%08x ", section, subsection, value);
133 vprintf(fmt, ap);
134 printf("\n");
135 va_end(ap);
136 }
137
print_path(const char * section,const char * subsection,const char * fmt,...)138 void print_path(const char *section, const char *subsection, const char *fmt, ...) {
139 va_list ap;
140
141 va_start(ap, fmt);
142 printf("%-12s %-12s .......... ", section, subsection);
143 vprintf(fmt, ap);
144 printf("\n");
145 va_end(ap);
146 }
147
resource_metadata(const AssetManager & am,uint32_t res_id,String8 * package,String8 * type,String8 * name)148 status_t resource_metadata(const AssetManager& am, uint32_t res_id,
149 String8 *package, String8 *type, String8 *name) {
150 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);
154 return UNKNOWN_ERROR;
155 }
156 if (package != NULL) {
157 *package = String8(String16(data.package, data.packageLen));
158 }
159 if (type != NULL) {
160 *type = String8(String16(data.type, data.typeLen));
161 }
162 if (name != NULL) {
163 *name = String8(String16(data.name, data.nameLen));
164 }
165 return NO_ERROR;
166 }
167
parse_idmap_header(IdmapBuffer & buf,AssetManager & am)168 status_t parse_idmap_header(IdmapBuffer& buf, AssetManager& am) {
169 uint32_t i;
170 char path[PATH_LENGTH];
171
172 status_t err = buf.nextUint32(&i);
173 if (err != NO_ERROR) {
174 return err;
175 }
176
177 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);
180 return UNKNOWN_ERROR;
181 }
182
183 print_header();
184 print("IDMAP HEADER", "magic", i, "");
185
186 err = buf.nextUint32(&i);
187 if (err != NO_ERROR) {
188 return err;
189 }
190 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
211 if (!am.addAssetPath(String8(path), NULL)) {
212 printe("failed to add '%s' as asset path\n", path);
213 return UNKNOWN_ERROR;
214 }
215
216 err = buf.nextPath(path);
217 if (err != NO_ERROR) {
218 // printe done from IdmapBuffer::nextPath
219 return err;
220 }
221 print_path("", "overlay path", "%s", path);
222
223 return NO_ERROR;
224 }
225
parse_data(IdmapBuffer & buf,const AssetManager & am)226 status_t parse_data(IdmapBuffer& buf, const AssetManager& am) {
227 const uint32_t packageId = am.getResources().getBasePackageId(0);
228
229 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), "");
235
236 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);
281 String8 type;
282 String8 name;
283 err = resource_metadata(am, resID, NULL, &type, &name);
284 if (err != NO_ERROR) {
285 return err;
286 }
287 if (data32 != ResTable_type::NO_ENTRY) {
288 print("", "entry", data32, "%s/%s", type.string(), name.string());
289 }
290 }
291 }
292
293 return NO_ERROR;
294 }
295 }
296
idmap_inspect(const char * idmap_path)297 int idmap_inspect(const char *idmap_path) {
298 IdmapBuffer buf;
299 if (buf.init(idmap_path) < 0) {
300 // printe done from IdmapBuffer::init
301 return EXIT_FAILURE;
302 }
303 AssetManager am;
304 if (parse_idmap_header(buf, am) != NO_ERROR) {
305 // printe done from parse_idmap_header
306 return EXIT_FAILURE;
307 }
308 if (parse_data(buf, am) != NO_ERROR) {
309 // printe done from parse_data_header
310 return EXIT_FAILURE;
311 }
312 return EXIT_SUCCESS;
313 }
314