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