Home | History | Annotate | Download | only in idmap
      1 #include "idmap.h"
      2 
      3 #include <UniquePtr.h>
      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         UniquePtr<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 | LOCK_NB)) != 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, SEEK_SET, 0) < 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, SEEK_SET, 0) < 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 cached_target_crc, cached_overlay_crc;
    108         String8 cached_target_path, cached_overlay_path;
    109         if (!ResTable::getIdmapInfo(buf, N, NULL, &cached_target_crc, &cached_overlay_crc,
    110                     &cached_target_path, &cached_overlay_path)) {
    111             return true;
    112         }
    113 
    114         if (cached_target_path != target_apk_path) {
    115             return true;
    116         }
    117         if (cached_overlay_path != overlay_apk_path) {
    118             return true;
    119         }
    120 
    121         uint32_t actual_target_crc, actual_overlay_crc;
    122         if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
    123 				&actual_target_crc) == -1) {
    124             return true;
    125         }
    126         if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
    127 				&actual_overlay_crc) == -1) {
    128             return true;
    129         }
    130 
    131         return cached_target_crc != actual_target_crc || cached_overlay_crc != actual_overlay_crc;
    132     }
    133 
    134     bool is_idmap_stale_path(const char *target_apk_path, const char *overlay_apk_path,
    135             const char *idmap_path)
    136     {
    137         struct stat st;
    138         if (stat(idmap_path, &st) == -1) {
    139             // non-existing idmap is always stale; on other errors, abort idmap generation
    140             return errno == ENOENT;
    141         }
    142 
    143         int idmap_fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY));
    144         if (idmap_fd == -1) {
    145             return false;
    146         }
    147         bool is_stale = is_idmap_stale_fd(target_apk_path, overlay_apk_path, idmap_fd);
    148         close(idmap_fd);
    149         return is_stale;
    150     }
    151 
    152     int create_idmap(const char *target_apk_path, const char *overlay_apk_path,
    153             uint32_t **data, size_t *size)
    154     {
    155         uint32_t target_crc, overlay_crc;
    156         if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
    157 				&target_crc) == -1) {
    158             return -1;
    159         }
    160         if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
    161 				&overlay_crc) == -1) {
    162             return -1;
    163         }
    164 
    165         AssetManager am;
    166         bool b = am.createIdmap(target_apk_path, overlay_apk_path, target_crc, overlay_crc,
    167                 data, size);
    168         return b ? 0 : -1;
    169     }
    170 
    171     int create_and_write_idmap(const char *target_apk_path, const char *overlay_apk_path,
    172             int fd, bool check_if_stale)
    173     {
    174         if (check_if_stale) {
    175             if (!is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd)) {
    176                 // already up to date -- nothing to do
    177                 return 0;
    178             }
    179         }
    180 
    181         uint32_t *data = NULL;
    182         size_t size;
    183 
    184         if (create_idmap(target_apk_path, overlay_apk_path, &data, &size) == -1) {
    185             return -1;
    186         }
    187 
    188         if (write_idmap(fd, data, size) == -1) {
    189             free(data);
    190             return -1;
    191         }
    192 
    193         free(data);
    194         return 0;
    195     }
    196 }
    197 
    198 int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path,
    199         const char *idmap_path)
    200 {
    201     if (!is_idmap_stale_path(target_apk_path, overlay_apk_path, idmap_path)) {
    202         // already up to date -- nothing to do
    203         return EXIT_SUCCESS;
    204     }
    205 
    206     int fd = open_idmap(idmap_path);
    207     if (fd == -1) {
    208         return EXIT_FAILURE;
    209     }
    210 
    211     int r = create_and_write_idmap(target_apk_path, overlay_apk_path, fd, false);
    212     close(fd);
    213     if (r != 0) {
    214         unlink(idmap_path);
    215     }
    216     return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
    217 }
    218 
    219 int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd)
    220 {
    221     return create_and_write_idmap(target_apk_path, overlay_apk_path, fd, true) == 0 ?
    222         EXIT_SUCCESS : EXIT_FAILURE;
    223 }
    224