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