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