From 13221c9cffdb289851411bdc73a9a5236fcb9291 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 11 Feb 2014 18:04:44 -0800 Subject: frameworks/base: move idmap from frameworks/native idmap depends on libandroidfw, so it should go in frameworks/base. Change-Id: I3c1db3baa355f53d6b523d60f4377e63eff00c30 --- cmds/idmap/create.cpp | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 cmds/idmap/create.cpp (limited to 'cmds/idmap/create.cpp') diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp new file mode 100644 index 0000000..ae35f7b --- /dev/null +++ b/cmds/idmap/create.cpp @@ -0,0 +1,222 @@ +#include "idmap.h" + +#include +#include +#include +#include +#include + +#include +#include + +using namespace android; + +namespace { + int get_zip_entry_crc(const char *zip_path, const char *entry_name, uint32_t *crc) + { + UniquePtr zip(ZipFileRO::open(zip_path)); + if (zip.get() == NULL) { + return -1; + } + ZipEntryRO entry = zip->findEntryByName(entry_name); + if (entry == NULL) { + return -1; + } + if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)crc)) { + return -1; + } + zip->releaseEntry(entry); + return 0; + } + + int open_idmap(const char *path) + { + int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)); + if (fd == -1) { + ALOGD("error: open %s: %s\n", path, strerror(errno)); + goto fail; + } + if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) { + ALOGD("error: fchmod %s: %s\n", path, strerror(errno)); + goto fail; + } + if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX | LOCK_NB)) != 0) { + ALOGD("error: flock %s: %s\n", path, strerror(errno)); + goto fail; + } + + return fd; +fail: + if (fd != -1) { + close(fd); + unlink(path); + } + return -1; + } + + int write_idmap(int fd, const uint32_t *data, size_t size) + { + if (lseek(fd, SEEK_SET, 0) < 0) { + return -1; + } + size_t bytesLeft = size; + while (bytesLeft > 0) { + ssize_t w = TEMP_FAILURE_RETRY(write(fd, data + size - bytesLeft, bytesLeft)); + if (w < 0) { + fprintf(stderr, "error: write: %s\n", strerror(errno)); + return -1; + } + bytesLeft -= w; + } + return 0; + } + + bool is_idmap_stale_fd(const char *target_apk_path, const char *overlay_apk_path, int idmap_fd) + { + static const size_t N = ResTable::IDMAP_HEADER_SIZE_BYTES; + struct stat st; + if (fstat(idmap_fd, &st) == -1) { + return true; + } + if (st.st_size < N) { + // file is empty or corrupt + return true; + } + + char buf[N]; + ssize_t bytesLeft = N; + if (lseek(idmap_fd, SEEK_SET, 0) < 0) { + return true; + } + for (;;) { + ssize_t r = TEMP_FAILURE_RETRY(read(idmap_fd, buf + N - bytesLeft, bytesLeft)); + if (r < 0) { + return true; + } + bytesLeft -= r; + if (bytesLeft == 0) { + break; + } + if (r == 0) { + // "shouldn't happen" + return true; + } + } + + uint32_t cached_target_crc, cached_overlay_crc; + String8 cached_target_path, cached_overlay_path; + if (!ResTable::getIdmapInfo(buf, N, &cached_target_crc, &cached_overlay_crc, + &cached_target_path, &cached_overlay_path)) { + return true; + } + + if (cached_target_path != target_apk_path) { + return true; + } + if (cached_overlay_path != overlay_apk_path) { + return true; + } + + uint32_t actual_target_crc, actual_overlay_crc; + if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME, + &actual_target_crc) == -1) { + return true; + } + if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME, + &actual_overlay_crc) == -1) { + return true; + } + + return cached_target_crc != actual_target_crc || cached_overlay_crc != actual_overlay_crc; + } + + bool is_idmap_stale_path(const char *target_apk_path, const char *overlay_apk_path, + const char *idmap_path) + { + struct stat st; + if (stat(idmap_path, &st) == -1) { + // non-existing idmap is always stale; on other errors, abort idmap generation + return errno == ENOENT; + } + + int idmap_fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY)); + if (idmap_fd == -1) { + return false; + } + bool is_stale = is_idmap_stale_fd(target_apk_path, overlay_apk_path, idmap_fd); + close(idmap_fd); + return is_stale; + } + + int create_idmap(const char *target_apk_path, const char *overlay_apk_path, + uint32_t **data, size_t *size) + { + uint32_t target_crc, overlay_crc; + if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME, + &target_crc) == -1) { + return -1; + } + if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME, + &overlay_crc) == -1) { + return -1; + } + + AssetManager am; + bool b = am.createIdmap(target_apk_path, overlay_apk_path, target_crc, overlay_crc, + data, size); + return b ? 0 : -1; + } + + int create_and_write_idmap(const char *target_apk_path, const char *overlay_apk_path, + int fd, bool check_if_stale) + { + if (check_if_stale) { + if (!is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd)) { + // already up to date -- nothing to do + return 0; + } + } + + uint32_t *data = NULL; + size_t size; + + if (create_idmap(target_apk_path, overlay_apk_path, &data, &size) == -1) { + return -1; + } + + if (write_idmap(fd, data, size) == -1) { + free(data); + return -1; + } + + free(data); + return 0; + } +} + +int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path, + const char *idmap_path) +{ + if (!is_idmap_stale_path(target_apk_path, overlay_apk_path, idmap_path)) { + // already up to date -- nothing to do + return EXIT_SUCCESS; + } + + int fd = open_idmap(idmap_path); + if (fd == -1) { + return EXIT_FAILURE; + } + + int r = create_and_write_idmap(target_apk_path, overlay_apk_path, fd, false); + close(fd); + if (r != 0) { + unlink(idmap_path); + } + return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd) +{ + return create_and_write_idmap(target_apk_path, overlay_apk_path, fd, true) == 0 ? + EXIT_SUCCESS : EXIT_FAILURE; +} -- cgit v1.1