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