Home | History | Annotate | Download | only in idmap
      1 #include "idmap.h"
      2 
      3 #include <memory>
      4 #include <androidfw/AssetManager.h>
      5 #include <androidfw/ResourceTypes.h>
      6 #include <androidfw/ZipFileRO.h>
      7 #include <utils/String8.h>
      8 
      9 #include <fcntl.h>
     10 #include <sys/file.h>
     11 #include <sys/stat.h>
     12 
     13 using namespace android;
     14 
     15 namespace {
     16     int get_zip_entry_crc(const char *zip_path, const char *entry_name, uint32_t *crc)
     17     {
     18         std::unique_ptr<ZipFileRO> zip(ZipFileRO::open(zip_path));
     19         if (zip.get() == NULL) {
     20             return -1;
     21         }
     22         ZipEntryRO entry = zip->findEntryByName(entry_name);
     23         if (entry == NULL) {
     24             return -1;
     25         }
     26         if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, crc)) {
     27             return -1;
     28         }
     29         zip->releaseEntry(entry);
     30         return 0;
     31     }
     32 
     33     int open_idmap(const char *path)
     34     {
     35         int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644));
     36         if (fd == -1) {
     37             ALOGD("error: open %s: %s\n", path, strerror(errno));
     38             goto fail;
     39         }
     40         if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
     41             ALOGD("error: fchmod %s: %s\n", path, strerror(errno));
     42             goto fail;
     43         }
     44         if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX)) != 0) {
     45             ALOGD("error: flock %s: %s\n", path, strerror(errno));
     46             goto fail;
     47         }
     48 
     49         return fd;
     50 fail:
     51         if (fd != -1) {
     52             close(fd);
     53             unlink(path);
     54         }
     55         return -1;
     56     }
     57 
     58     int write_idmap(int fd, const uint32_t *data, size_t size)
     59     {
     60         if (lseek(fd, 0, SEEK_SET) < 0) {
     61             return -1;
     62         }
     63         size_t bytesLeft = size;
     64         while (bytesLeft > 0) {
     65             ssize_t w = TEMP_FAILURE_RETRY(write(fd, data + size - bytesLeft, bytesLeft));
     66             if (w < 0) {
     67                 fprintf(stderr, "error: write: %s\n", strerror(errno));
     68                 return -1;
     69             }
     70             bytesLeft -= static_cast<size_t>(w);
     71         }
     72         return 0;
     73     }
     74 
     75     bool is_idmap_stale_fd(const char *target_apk_path, const char *overlay_apk_path, int idmap_fd)
     76     {
     77         static const size_t N = ResTable::IDMAP_HEADER_SIZE_BYTES;
     78         struct stat st;
     79         if (fstat(idmap_fd, &st) == -1) {
     80             return true;
     81         }
     82         if (st.st_size < static_cast<off_t>(N)) {
     83             // file is empty or corrupt
     84             return true;
     85         }
     86 
     87         char buf[N];
     88         size_t bytesLeft = N;
     89         if (lseek(idmap_fd, 0, SEEK_SET) < 0) {
     90             return true;
     91         }
     92         for (;;) {
     93             ssize_t r = TEMP_FAILURE_RETRY(read(idmap_fd, buf + N - bytesLeft, bytesLeft));
     94             if (r < 0) {
     95                 return true;
     96             }
     97             bytesLeft -= static_cast<size_t>(r);
     98             if (bytesLeft == 0) {
     99                 break;
    100             }
    101             if (r == 0) {
    102                 // "shouldn't happen"
    103                 return true;
    104             }
    105         }
    106 
    107         uint32_t version, cached_target_crc, cached_overlay_crc;
    108         String8 cached_target_path, cached_overlay_path;
    109         if (!ResTable::getIdmapInfo(buf, N, &version, &cached_target_crc, &cached_overlay_crc,
    110                     &cached_target_path, &cached_overlay_path)) {
    111             return true;
    112         }
    113 
    114         if (version != ResTable::IDMAP_CURRENT_VERSION) {
    115             return true;
    116         }
    117 
    118         if (cached_target_path != target_apk_path) {
    119             return true;
    120         }
    121         if (cached_overlay_path != overlay_apk_path) {
    122             return true;
    123         }
    124 
    125         uint32_t actual_target_crc, actual_overlay_crc;
    126         if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
    127 				&actual_target_crc) == -1) {
    128             return true;
    129         }
    130         if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
    131 				&actual_overlay_crc) == -1) {
    132             return true;
    133         }
    134 
    135         return cached_target_crc != actual_target_crc || cached_overlay_crc != actual_overlay_crc;
    136     }
    137 
    138     bool is_idmap_stale_path(const char *target_apk_path, const char *overlay_apk_path,
    139             const char *idmap_path)
    140     {
    141         struct stat st;
    142         if (stat(idmap_path, &st) == -1) {
    143             // non-existing idmap is always stale; on other errors, abort idmap generation
    144             return errno == ENOENT;
    145         }
    146 
    147         int idmap_fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY));
    148         if (idmap_fd == -1) {
    149             return false;
    150         }
    151         bool is_stale = is_idmap_stale_fd(target_apk_path, overlay_apk_path, idmap_fd);
    152         close(idmap_fd);
    153         return is_stale;
    154     }
    155 
    156     int create_idmap(const char *target_apk_path, const char *overlay_apk_path,
    157             uint32_t **data, size_t *size)
    158     {
    159         uint32_t target_crc, overlay_crc;
    160         if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
    161 				&target_crc) == -1) {
    162             return -1;
    163         }
    164         if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
    165 				&overlay_crc) == -1) {
    166             return -1;
    167         }
    168 
    169         AssetManager am;
    170         bool b = am.createIdmap(target_apk_path, overlay_apk_path, target_crc, overlay_crc,
    171                 data, size);
    172         return b ? 0 : -1;
    173     }
    174 
    175     int create_and_write_idmap(const char *target_apk_path, const char *overlay_apk_path,
    176             int fd, bool check_if_stale)
    177     {
    178         if (check_if_stale) {
    179             if (!is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd)) {
    180                 // already up to date -- nothing to do
    181                 return 0;
    182             }
    183         }
    184 
    185         uint32_t *data = NULL;
    186         size_t size;
    187 
    188         if (create_idmap(target_apk_path, overlay_apk_path, &data, &size) == -1) {
    189             return -1;
    190         }
    191 
    192         if (write_idmap(fd, data, size) == -1) {
    193             free(data);
    194             return -1;
    195         }
    196 
    197         free(data);
    198         return 0;
    199     }
    200 }
    201 
    202 int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path,
    203         const char *idmap_path)
    204 {
    205     if (!is_idmap_stale_path(target_apk_path, overlay_apk_path, idmap_path)) {
    206         // already up to date -- nothing to do
    207         return EXIT_SUCCESS;
    208     }
    209 
    210     int fd = open_idmap(idmap_path);
    211     if (fd == -1) {
    212         return EXIT_FAILURE;
    213     }
    214 
    215     int r = create_and_write_idmap(target_apk_path, overlay_apk_path, fd, false);
    216     close(fd);
    217     if (r != 0) {
    218         unlink(idmap_path);
    219     }
    220     return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
    221 }
    222 
    223 int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd)
    224 {
    225     return create_and_write_idmap(target_apk_path, overlay_apk_path, fd, true) == 0 ?
    226         EXIT_SUCCESS : EXIT_FAILURE;
    227 }
    228 
    229 int idmap_verify_fd(const char *target_apk_path, const char *overlay_apk_path, int fd)
    230 {
    231     return !is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd) ?
    232             EXIT_SUCCESS : EXIT_FAILURE;
    233 }
    234