113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include "idmap.h" 213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <UniquePtr.h> 413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <androidfw/AssetManager.h> 513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <androidfw/ResourceTypes.h> 613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <androidfw/ZipFileRO.h> 713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <utils/String8.h> 813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <fcntl.h> 10b9de25f7db14102518485ad8375784848a200e60Elliott Hughes#include <sys/file.h> 1113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <sys/stat.h> 1213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 1313221c9cffdb289851411bdc73a9a5236fcb9291Colin Crossusing namespace android; 1413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 1513221c9cffdb289851411bdc73a9a5236fcb9291Colin Crossnamespace { 1613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross int get_zip_entry_crc(const char *zip_path, const char *entry_name, uint32_t *crc) 1713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross { 1813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross UniquePtr<ZipFileRO> zip(ZipFileRO::open(zip_path)); 1913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (zip.get() == NULL) { 2013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return -1; 2113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 2213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross ZipEntryRO entry = zip->findEntryByName(entry_name); 2313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (entry == NULL) { 2413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return -1; 2513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 264600dd053dbdbd4b95f3b11057a1cc55b99f9c77Narayan Kamath if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, crc)) { 2713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return -1; 2813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 2913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross zip->releaseEntry(entry); 3013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return 0; 3113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 3213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 3313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross int open_idmap(const char *path) 3413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross { 3513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)); 3613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (fd == -1) { 3713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross ALOGD("error: open %s: %s\n", path, strerror(errno)); 3813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross goto fail; 3913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 4013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) { 4113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross ALOGD("error: fchmod %s: %s\n", path, strerror(errno)); 4213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross goto fail; 4313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 4413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX | LOCK_NB)) != 0) { 4513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross ALOGD("error: flock %s: %s\n", path, strerror(errno)); 4613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross goto fail; 4713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 4813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 4913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return fd; 5013221c9cffdb289851411bdc73a9a5236fcb9291Colin Crossfail: 5113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (fd != -1) { 5213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross close(fd); 5313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross unlink(path); 5413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 5513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return -1; 5613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 5713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 5813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross int write_idmap(int fd, const uint32_t *data, size_t size) 5913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross { 6013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (lseek(fd, SEEK_SET, 0) < 0) { 6113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return -1; 6213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 6313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross size_t bytesLeft = size; 6413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross while (bytesLeft > 0) { 6513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross ssize_t w = TEMP_FAILURE_RETRY(write(fd, data + size - bytesLeft, bytesLeft)); 6613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (w < 0) { 6713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross fprintf(stderr, "error: write: %s\n", strerror(errno)); 6813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return -1; 6913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 70cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe bytesLeft -= static_cast<size_t>(w); 7113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 7213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return 0; 7313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 7413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 7513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross bool is_idmap_stale_fd(const char *target_apk_path, const char *overlay_apk_path, int idmap_fd) 7613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross { 7713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross static const size_t N = ResTable::IDMAP_HEADER_SIZE_BYTES; 7813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross struct stat st; 7913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (fstat(idmap_fd, &st) == -1) { 8013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return true; 8113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 82ebee1379eaf4306eb2de9437844009aa7eb18c28Andreas Gampe if (st.st_size < static_cast<off_t>(N)) { 8313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross // file is empty or corrupt 8413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return true; 8513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 8613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 8713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross char buf[N]; 88cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe size_t bytesLeft = N; 8913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (lseek(idmap_fd, SEEK_SET, 0) < 0) { 9013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return true; 9113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 9213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross for (;;) { 9313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross ssize_t r = TEMP_FAILURE_RETRY(read(idmap_fd, buf + N - bytesLeft, bytesLeft)); 9413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (r < 0) { 9513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return true; 9613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 97cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe bytesLeft -= static_cast<size_t>(r); 9813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (bytesLeft == 0) { 9913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross break; 10013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 10113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (r == 0) { 10213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross // "shouldn't happen" 10313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return true; 10413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 10513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 10613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 10713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross uint32_t cached_target_crc, cached_overlay_crc; 10813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross String8 cached_target_path, cached_overlay_path; 109f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski if (!ResTable::getIdmapInfo(buf, N, NULL, &cached_target_crc, &cached_overlay_crc, 11013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross &cached_target_path, &cached_overlay_path)) { 11113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return true; 11213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 11313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 11413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (cached_target_path != target_apk_path) { 11513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return true; 11613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 11713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (cached_overlay_path != overlay_apk_path) { 11813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return true; 11913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 12013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 12113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross uint32_t actual_target_crc, actual_overlay_crc; 12213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME, 12313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross &actual_target_crc) == -1) { 12413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return true; 12513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 12613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME, 12713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross &actual_overlay_crc) == -1) { 12813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return true; 12913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 13013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 13113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return cached_target_crc != actual_target_crc || cached_overlay_crc != actual_overlay_crc; 13213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 13313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 13413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross bool is_idmap_stale_path(const char *target_apk_path, const char *overlay_apk_path, 13513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross const char *idmap_path) 13613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross { 13713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross struct stat st; 13813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (stat(idmap_path, &st) == -1) { 13913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross // non-existing idmap is always stale; on other errors, abort idmap generation 14013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return errno == ENOENT; 14113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 14213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 14313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross int idmap_fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY)); 14413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (idmap_fd == -1) { 14513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return false; 14613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 14713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross bool is_stale = is_idmap_stale_fd(target_apk_path, overlay_apk_path, idmap_fd); 14813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross close(idmap_fd); 14913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return is_stale; 15013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 15113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 15213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross int create_idmap(const char *target_apk_path, const char *overlay_apk_path, 15313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross uint32_t **data, size_t *size) 15413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross { 15513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross uint32_t target_crc, overlay_crc; 15613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME, 15713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross &target_crc) == -1) { 15813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return -1; 15913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 16013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME, 16113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross &overlay_crc) == -1) { 16213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return -1; 16313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 16413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 16513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross AssetManager am; 16613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross bool b = am.createIdmap(target_apk_path, overlay_apk_path, target_crc, overlay_crc, 16713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross data, size); 16813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return b ? 0 : -1; 16913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 17013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 17113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross int create_and_write_idmap(const char *target_apk_path, const char *overlay_apk_path, 17213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross int fd, bool check_if_stale) 17313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross { 17413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (check_if_stale) { 17513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (!is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd)) { 17613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross // already up to date -- nothing to do 17713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return 0; 17813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 17913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 18013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 18113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross uint32_t *data = NULL; 18213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross size_t size; 18313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 18413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (create_idmap(target_apk_path, overlay_apk_path, &data, &size) == -1) { 18513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return -1; 18613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 18713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 18813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (write_idmap(fd, data, size) == -1) { 18913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross free(data); 19013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return -1; 19113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 19213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 19313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross free(data); 19413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return 0; 19513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 19613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross} 19713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 19813221c9cffdb289851411bdc73a9a5236fcb9291Colin Crossint idmap_create_path(const char *target_apk_path, const char *overlay_apk_path, 19913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross const char *idmap_path) 20013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross{ 20113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (!is_idmap_stale_path(target_apk_path, overlay_apk_path, idmap_path)) { 20213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross // already up to date -- nothing to do 20313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return EXIT_SUCCESS; 20413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 20513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 20613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross int fd = open_idmap(idmap_path); 20713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (fd == -1) { 20813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return EXIT_FAILURE; 20913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 21013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 21113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross int r = create_and_write_idmap(target_apk_path, overlay_apk_path, fd, false); 21213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross close(fd); 21313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross if (r != 0) { 21413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross unlink(idmap_path); 21513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross } 21613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 21713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross} 21813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross 21913221c9cffdb289851411bdc73a9a5236fcb9291Colin Crossint idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd) 22013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross{ 22113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross return create_and_write_idmap(target_apk_path, overlay_apk_path, fd, true) == 0 ? 22213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross EXIT_SUCCESS : EXIT_FAILURE; 22313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross} 224