blob: f415f8f5dd75e0608e37b26bea9c9947a9461b60 [file] [log] [blame]
Colin Cross13221c92014-02-11 18:04:44 -08001#include "idmap.h"
2
Dan Albert0881a742015-11-05 00:57:12 -08003#include <memory>
Colin Cross13221c92014-02-11 18:04:44 -08004#include <androidfw/AssetManager.h>
5#include <androidfw/ResourceTypes.h>
6#include <androidfw/ZipFileRO.h>
7#include <utils/String8.h>
8
9#include <fcntl.h>
Elliott Hughesb9de25f2015-02-16 10:43:19 -080010#include <sys/file.h>
Colin Cross13221c92014-02-11 18:04:44 -080011#include <sys/stat.h>
12
13using namespace android;
14
15namespace {
16 int get_zip_entry_crc(const char *zip_path, const char *entry_name, uint32_t *crc)
17 {
Dan Albert0881a742015-11-05 00:57:12 -080018 std::unique_ptr<ZipFileRO> zip(ZipFileRO::open(zip_path));
Colin Cross13221c92014-02-11 18:04:44 -080019 if (zip.get() == NULL) {
20 return -1;
21 }
22 ZipEntryRO entry = zip->findEntryByName(entry_name);
23 if (entry == NULL) {
24 return -1;
25 }
Narayan Kamath4600dd02015-06-16 12:02:57 +010026 if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, crc)) {
Colin Cross13221c92014-02-11 18:04:44 -080027 return -1;
28 }
29 zip->releaseEntry(entry);
30 return 0;
31 }
32
33 int open_idmap(const char *path)
34 {
35 int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644));
36 if (fd == -1) {
37 ALOGD("error: open %s: %s\n", path, strerror(errno));
38 goto fail;
39 }
40 if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
41 ALOGD("error: fchmod %s: %s\n", path, strerror(errno));
42 goto fail;
43 }
Mårten Kongstaddf1a5b22015-03-18 15:18:10 +010044 if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX)) != 0) {
Colin Cross13221c92014-02-11 18:04:44 -080045 ALOGD("error: flock %s: %s\n", path, strerror(errno));
46 goto fail;
47 }
48
49 return fd;
50fail:
51 if (fd != -1) {
52 close(fd);
53 unlink(path);
54 }
55 return -1;
56 }
57
58 int write_idmap(int fd, const uint32_t *data, size_t size)
59 {
Elliott Hughes70bef1c2015-10-20 13:23:18 -070060 if (lseek(fd, 0, SEEK_SET) < 0) {
Colin Cross13221c92014-02-11 18:04:44 -080061 return -1;
62 }
63 size_t bytesLeft = size;
64 while (bytesLeft > 0) {
65 ssize_t w = TEMP_FAILURE_RETRY(write(fd, data + size - bytesLeft, bytesLeft));
66 if (w < 0) {
67 fprintf(stderr, "error: write: %s\n", strerror(errno));
68 return -1;
69 }
Andreas Gampecfedceb2014-09-30 21:48:18 -070070 bytesLeft -= static_cast<size_t>(w);
Colin Cross13221c92014-02-11 18:04:44 -080071 }
72 return 0;
73 }
74
75 bool is_idmap_stale_fd(const char *target_apk_path, const char *overlay_apk_path, int idmap_fd)
76 {
77 static const size_t N = ResTable::IDMAP_HEADER_SIZE_BYTES;
78 struct stat st;
79 if (fstat(idmap_fd, &st) == -1) {
80 return true;
81 }
Andreas Gampeebee1372014-11-07 16:28:19 -080082 if (st.st_size < static_cast<off_t>(N)) {
Colin Cross13221c92014-02-11 18:04:44 -080083 // file is empty or corrupt
84 return true;
85 }
86
87 char buf[N];
Andreas Gampecfedceb2014-09-30 21:48:18 -070088 size_t bytesLeft = N;
Elliott Hughes70bef1c2015-10-20 13:23:18 -070089 if (lseek(idmap_fd, 0, SEEK_SET) < 0) {
Colin Cross13221c92014-02-11 18:04:44 -080090 return true;
91 }
92 for (;;) {
93 ssize_t r = TEMP_FAILURE_RETRY(read(idmap_fd, buf + N - bytesLeft, bytesLeft));
94 if (r < 0) {
95 return true;
96 }
Andreas Gampecfedceb2014-09-30 21:48:18 -070097 bytesLeft -= static_cast<size_t>(r);
Colin Cross13221c92014-02-11 18:04:44 -080098 if (bytesLeft == 0) {
99 break;
100 }
101 if (r == 0) {
102 // "shouldn't happen"
103 return true;
104 }
105 }
106
Mårten Kongstad42ebcb82017-03-28 15:30:21 +0200107 uint32_t version, cached_target_crc, cached_overlay_crc;
Colin Cross13221c92014-02-11 18:04:44 -0800108 String8 cached_target_path, cached_overlay_path;
Mårten Kongstad42ebcb82017-03-28 15:30:21 +0200109 if (!ResTable::getIdmapInfo(buf, N, &version, &cached_target_crc, &cached_overlay_crc,
Colin Cross13221c92014-02-11 18:04:44 -0800110 &cached_target_path, &cached_overlay_path)) {
111 return true;
112 }
113
Mårten Kongstad42ebcb82017-03-28 15:30:21 +0200114 if (version != ResTable::IDMAP_CURRENT_VERSION) {
115 return true;
116 }
117
Colin Cross13221c92014-02-11 18:04:44 -0800118 if (cached_target_path != target_apk_path) {
119 return true;
120 }
121 if (cached_overlay_path != overlay_apk_path) {
122 return true;
123 }
124
125 uint32_t actual_target_crc, actual_overlay_crc;
126 if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
127 &actual_target_crc) == -1) {
128 return true;
129 }
130 if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
131 &actual_overlay_crc) == -1) {
132 return true;
133 }
134
135 return cached_target_crc != actual_target_crc || cached_overlay_crc != actual_overlay_crc;
136 }
137
138 bool is_idmap_stale_path(const char *target_apk_path, const char *overlay_apk_path,
139 const char *idmap_path)
140 {
141 struct stat st;
142 if (stat(idmap_path, &st) == -1) {
143 // non-existing idmap is always stale; on other errors, abort idmap generation
144 return errno == ENOENT;
145 }
146
147 int idmap_fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY));
148 if (idmap_fd == -1) {
149 return false;
150 }
151 bool is_stale = is_idmap_stale_fd(target_apk_path, overlay_apk_path, idmap_fd);
152 close(idmap_fd);
153 return is_stale;
154 }
155
156 int create_idmap(const char *target_apk_path, const char *overlay_apk_path,
157 uint32_t **data, size_t *size)
158 {
159 uint32_t target_crc, overlay_crc;
160 if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
161 &target_crc) == -1) {
162 return -1;
163 }
164 if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
165 &overlay_crc) == -1) {
166 return -1;
167 }
168
169 AssetManager am;
170 bool b = am.createIdmap(target_apk_path, overlay_apk_path, target_crc, overlay_crc,
171 data, size);
172 return b ? 0 : -1;
173 }
174
175 int create_and_write_idmap(const char *target_apk_path, const char *overlay_apk_path,
176 int fd, bool check_if_stale)
177 {
178 if (check_if_stale) {
179 if (!is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd)) {
180 // already up to date -- nothing to do
181 return 0;
182 }
183 }
184
185 uint32_t *data = NULL;
186 size_t size;
187
188 if (create_idmap(target_apk_path, overlay_apk_path, &data, &size) == -1) {
189 return -1;
190 }
191
192 if (write_idmap(fd, data, size) == -1) {
193 free(data);
194 return -1;
195 }
196
197 free(data);
198 return 0;
199 }
200}
201
202int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path,
203 const char *idmap_path)
204{
205 if (!is_idmap_stale_path(target_apk_path, overlay_apk_path, idmap_path)) {
206 // already up to date -- nothing to do
207 return EXIT_SUCCESS;
208 }
209
210 int fd = open_idmap(idmap_path);
211 if (fd == -1) {
212 return EXIT_FAILURE;
213 }
214
215 int r = create_and_write_idmap(target_apk_path, overlay_apk_path, fd, false);
216 close(fd);
217 if (r != 0) {
218 unlink(idmap_path);
219 }
220 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
221}
222
223int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd)
224{
225 return create_and_write_idmap(target_apk_path, overlay_apk_path, fd, true) == 0 ?
226 EXIT_SUCCESS : EXIT_FAILURE;
227}
Jaekyun Seok71693e62017-05-18 00:10:57 +0900228
229int idmap_verify_fd(const char *target_apk_path, const char *overlay_apk_path, int fd)
230{
231 return !is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd) ?
232 EXIT_SUCCESS : EXIT_FAILURE;
233}