Home | History | Annotate | Download | only in idmap
      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 }
    312