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