OSDN Git Service

Merge "Cherry-pick 7ad1110ecd6a840fcd2895c62668828a1ca029c6"
[android-x86/frameworks-base.git] / cmds / idmap / inspect.cpp
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:
26             IdmapBuffer() : buf_((const char *)MAP_FAILED), len_(0), pos_(0) {}
27
28             ~IdmapBuffer() {
29                 if (buf_ != MAP_FAILED) {
30                     munmap(const_cast<char*>(buf_), len_);
31                 }
32             }
33
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
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
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
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
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
124     void print_header() {
125         printf("SECTION      ENTRY        VALUE      COMMENT\n");
126     }
127
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
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
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
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
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                 print("", "entry", data32, "%s/%s", type.string(), name.string());
288             }
289         }
290
291         return NO_ERROR;
292     }
293 }
294
295 int idmap_inspect(const char *idmap_path) {
296     IdmapBuffer buf;
297     if (buf.init(idmap_path) < 0) {
298         // printe done from IdmapBuffer::init
299         return EXIT_FAILURE;
300     }
301     AssetManager am;
302     if (parse_idmap_header(buf, am) != NO_ERROR) {
303         // printe done from parse_idmap_header
304         return EXIT_FAILURE;
305     }
306     if (parse_data(buf, am) != NO_ERROR) {
307         // printe done from parse_data_header
308         return EXIT_FAILURE;
309     }
310     return EXIT_SUCCESS;
311 }