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: 25 IdmapBuffer() : buf_((const char *)MAP_FAILED), len_(0), pos_(0) {} 26 27 ~IdmapBuffer() { 28 if (buf_ != MAP_FAILED) { 29 munmap(const_cast<char*>(buf_), len_); 30 } 31 } 32 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 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 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 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 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 123 void print_header() { 124 printf("SECTION ENTRY VALUE COMMENT\n"); 125 } 126 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 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 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 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 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 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