• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "idmap.h"
2 
3 #include <UniquePtr.h>
4 #include <androidfw/AssetManager.h>
5 #include <androidfw/ResourceTypes.h>
6 #include <androidfw/ZipFileRO.h>
7 #include <utils/String8.h>
8 
9 #include <fcntl.h>
10 #include <sys/stat.h>
11 
12 using namespace android;
13 
14 namespace {
get_zip_entry_crc(const char * zip_path,const char * entry_name,uint32_t * crc)15     int get_zip_entry_crc(const char *zip_path, const char *entry_name, uint32_t *crc)
16     {
17         UniquePtr<ZipFileRO> zip(ZipFileRO::open(zip_path));
18         if (zip.get() == NULL) {
19             return -1;
20         }
21         ZipEntryRO entry = zip->findEntryByName(entry_name);
22         if (entry == NULL) {
23             return -1;
24         }
25         if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)crc)) {
26             return -1;
27         }
28         zip->releaseEntry(entry);
29         return 0;
30     }
31 
open_idmap(const char * path)32     int open_idmap(const char *path)
33     {
34         int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644));
35         if (fd == -1) {
36             ALOGD("error: open %s: %s\n", path, strerror(errno));
37             goto fail;
38         }
39         if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
40             ALOGD("error: fchmod %s: %s\n", path, strerror(errno));
41             goto fail;
42         }
43         if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX | LOCK_NB)) != 0) {
44             ALOGD("error: flock %s: %s\n", path, strerror(errno));
45             goto fail;
46         }
47 
48         return fd;
49 fail:
50         if (fd != -1) {
51             close(fd);
52             unlink(path);
53         }
54         return -1;
55     }
56 
write_idmap(int fd,const uint32_t * data,size_t size)57     int write_idmap(int fd, const uint32_t *data, size_t size)
58     {
59         if (lseek(fd, SEEK_SET, 0) < 0) {
60             return -1;
61         }
62         size_t bytesLeft = size;
63         while (bytesLeft > 0) {
64             ssize_t w = TEMP_FAILURE_RETRY(write(fd, data + size - bytesLeft, bytesLeft));
65             if (w < 0) {
66                 fprintf(stderr, "error: write: %s\n", strerror(errno));
67                 return -1;
68             }
69             bytesLeft -= w;
70         }
71         return 0;
72     }
73 
is_idmap_stale_fd(const char * target_apk_path,const char * overlay_apk_path,int idmap_fd)74     bool is_idmap_stale_fd(const char *target_apk_path, const char *overlay_apk_path, int idmap_fd)
75     {
76         static const size_t N = ResTable::IDMAP_HEADER_SIZE_BYTES;
77         struct stat st;
78         if (fstat(idmap_fd, &st) == -1) {
79             return true;
80         }
81         if (st.st_size < N) {
82             // file is empty or corrupt
83             return true;
84         }
85 
86         char buf[N];
87         ssize_t bytesLeft = N;
88         if (lseek(idmap_fd, SEEK_SET, 0) < 0) {
89             return true;
90         }
91         for (;;) {
92             ssize_t r = TEMP_FAILURE_RETRY(read(idmap_fd, buf + N - bytesLeft, bytesLeft));
93             if (r < 0) {
94                 return true;
95             }
96             bytesLeft -= r;
97             if (bytesLeft == 0) {
98                 break;
99             }
100             if (r == 0) {
101                 // "shouldn't happen"
102                 return true;
103             }
104         }
105 
106         uint32_t cached_target_crc, cached_overlay_crc;
107         String8 cached_target_path, cached_overlay_path;
108         if (!ResTable::getIdmapInfo(buf, N, NULL, &cached_target_crc, &cached_overlay_crc,
109                     &cached_target_path, &cached_overlay_path)) {
110             return true;
111         }
112 
113         if (cached_target_path != target_apk_path) {
114             return true;
115         }
116         if (cached_overlay_path != overlay_apk_path) {
117             return true;
118         }
119 
120         uint32_t actual_target_crc, actual_overlay_crc;
121         if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
122 				&actual_target_crc) == -1) {
123             return true;
124         }
125         if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
126 				&actual_overlay_crc) == -1) {
127             return true;
128         }
129 
130         return cached_target_crc != actual_target_crc || cached_overlay_crc != actual_overlay_crc;
131     }
132 
is_idmap_stale_path(const char * target_apk_path,const char * overlay_apk_path,const char * idmap_path)133     bool is_idmap_stale_path(const char *target_apk_path, const char *overlay_apk_path,
134             const char *idmap_path)
135     {
136         struct stat st;
137         if (stat(idmap_path, &st) == -1) {
138             // non-existing idmap is always stale; on other errors, abort idmap generation
139             return errno == ENOENT;
140         }
141 
142         int idmap_fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY));
143         if (idmap_fd == -1) {
144             return false;
145         }
146         bool is_stale = is_idmap_stale_fd(target_apk_path, overlay_apk_path, idmap_fd);
147         close(idmap_fd);
148         return is_stale;
149     }
150 
create_idmap(const char * target_apk_path,const char * overlay_apk_path,uint32_t ** data,size_t * size)151     int create_idmap(const char *target_apk_path, const char *overlay_apk_path,
152             uint32_t **data, size_t *size)
153     {
154         uint32_t target_crc, overlay_crc;
155         if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
156 				&target_crc) == -1) {
157             return -1;
158         }
159         if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
160 				&overlay_crc) == -1) {
161             return -1;
162         }
163 
164         AssetManager am;
165         bool b = am.createIdmap(target_apk_path, overlay_apk_path, target_crc, overlay_crc,
166                 data, size);
167         return b ? 0 : -1;
168     }
169 
create_and_write_idmap(const char * target_apk_path,const char * overlay_apk_path,int fd,bool check_if_stale)170     int create_and_write_idmap(const char *target_apk_path, const char *overlay_apk_path,
171             int fd, bool check_if_stale)
172     {
173         if (check_if_stale) {
174             if (!is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd)) {
175                 // already up to date -- nothing to do
176                 return 0;
177             }
178         }
179 
180         uint32_t *data = NULL;
181         size_t size;
182 
183         if (create_idmap(target_apk_path, overlay_apk_path, &data, &size) == -1) {
184             return -1;
185         }
186 
187         if (write_idmap(fd, data, size) == -1) {
188             free(data);
189             return -1;
190         }
191 
192         free(data);
193         return 0;
194     }
195 }
196 
idmap_create_path(const char * target_apk_path,const char * overlay_apk_path,const char * idmap_path)197 int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path,
198         const char *idmap_path)
199 {
200     if (!is_idmap_stale_path(target_apk_path, overlay_apk_path, idmap_path)) {
201         // already up to date -- nothing to do
202         return EXIT_SUCCESS;
203     }
204 
205     int fd = open_idmap(idmap_path);
206     if (fd == -1) {
207         return EXIT_FAILURE;
208     }
209 
210     int r = create_and_write_idmap(target_apk_path, overlay_apk_path, fd, false);
211     close(fd);
212     if (r != 0) {
213         unlink(idmap_path);
214     }
215     return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
216 }
217 
idmap_create_fd(const char * target_apk_path,const char * overlay_apk_path,int fd)218 int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd)
219 {
220     return create_and_write_idmap(target_apk_path, overlay_apk_path, fd, true) == 0 ?
221         EXIT_SUCCESS : EXIT_FAILURE;
222 }
223