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