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/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