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 12using namespace android; 13 14namespace { 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 295int 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} 312