blob: d69dd79555a1d1f222aed9631cce31566b4c3138 [file] [log] [blame]
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +09001#include <dirent.h>
2#include <inttypes.h>
3#include <sys/file.h>
4#include <sys/stat.h>
5
6#include "idmap.h"
7
8#include <memory>
9#include <androidfw/ResourceTypes.h>
10#include <androidfw/StreamingZipInflater.h>
11#include <androidfw/ZipFileRO.h>
Jaekyun Seok04342892017-03-02 15:24:19 +090012#include <cutils/jstring.h>
Todd Leed5566c62017-03-16 14:00:52 -070013#include <cutils/properties.h>
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +090014#include <private/android_filesystem_config.h> // for AID_SYSTEM
15#include <utils/SortedVector.h>
16#include <utils/String16.h>
17#include <utils/String8.h>
18
19#define NO_OVERLAY_TAG (-1000)
20
21using namespace android;
22
23namespace {
24 struct Overlay {
25 Overlay() {}
26 Overlay(const String8& a, const String8& i, int p) :
27 apk_path(a), idmap_path(i), priority(p) {}
28
29 bool operator<(Overlay const& rhs) const
30 {
31 return rhs.priority > priority;
32 }
33
34 String8 apk_path;
35 String8 idmap_path;
36 int priority;
37 };
38
39 bool writePackagesList(const char *filename, const SortedVector<Overlay>& overlayVector)
40 {
41 // the file is opened for appending so that it doesn't get truncated
42 // before we can guarantee mutual exclusion via the flock
43 FILE* fout = fopen(filename, "a");
44 if (fout == NULL) {
45 return false;
46 }
47
48 if (TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_EX)) != 0) {
49 fclose(fout);
50 return false;
51 }
52
53 if (TEMP_FAILURE_RETRY(ftruncate(fileno(fout), 0)) != 0) {
54 TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
55 fclose(fout);
56 return false;
57 }
58
59 for (size_t i = 0; i < overlayVector.size(); ++i) {
60 const Overlay& overlay = overlayVector[i];
61 fprintf(fout, "%s %s\n", overlay.apk_path.string(), overlay.idmap_path.string());
62 }
63
64 TEMP_FAILURE_RETRY(fflush(fout));
65 TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
66 fclose(fout);
67
68 // Make file world readable since Zygote (running as root) will read
69 // it when creating the initial AssetManger object
70 const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 0644
71 if (chmod(filename, mode) == -1) {
72 unlink(filename);
73 return false;
74 }
75
76 return true;
77 }
78
79 String8 flatten_path(const char *path)
80 {
81 String16 tmp(path);
82 tmp.replaceAll('/', '@');
83 return String8(tmp);
84 }
85
Todd Leed5566c62017-03-16 14:00:52 -070086 bool check_property(String16 property, String16 value) {
87 const char *prop;
88 const char *val;
89
90 prop = strndup16to8(property.string(), property.size());
91 char propBuf[PROPERTY_VALUE_MAX];
92 property_get(prop, propBuf, NULL);
93 val = strndup16to8(value.string(), value.size());
94
95 return (strcmp(propBuf, val) == 0);
96 }
97
Jaekyun Seok04342892017-03-02 15:24:19 +090098 int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name,
99 bool* is_static_overlay)
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900100 {
101 const size_t N = parser.getAttributeCount();
102 String16 target;
103 int priority = -1;
Todd Leed5566c62017-03-16 14:00:52 -0700104 String16 propName = String16();
105 String16 propValue = String16();
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900106 for (size_t i = 0; i < N; ++i) {
107 size_t len;
108 String16 key(parser.getAttributeName(i, &len));
109 if (key == String16("targetPackage")) {
110 const char16_t *p = parser.getAttributeStringValue(i, &len);
111 if (p != NULL) {
112 target = String16(p, len);
113 }
114 } else if (key == String16("priority")) {
115 Res_value v;
116 if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) {
117 priority = v.data;
118 if (priority < 0 || priority > 9999) {
119 return -1;
120 }
121 }
Jaekyun Seok04342892017-03-02 15:24:19 +0900122 } else if (key == String16("isStatic")) {
123 Res_value v;
124 if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) {
125 *is_static_overlay = (v.data != 0);
126 }
Todd Leed5566c62017-03-16 14:00:52 -0700127 } else if (key == String16("requiredSystemPropertyName")) {
128 const char16_t *p = parser.getAttributeStringValue(i, &len);
129 if (p != NULL) {
130 propName = String16(p, len);
131 }
132 } else if (key == String16("requiredSystemPropertyValue")) {
133 const char16_t *p = parser.getAttributeStringValue(i, &len);
134 if (p != NULL) {
135 propValue = String16(p, len);
136 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900137 }
138 }
Todd Leed5566c62017-03-16 14:00:52 -0700139
140 // Note that conditional property enablement/exclusion only applies if
141 // the attribute is present. In its absence, all overlays are presumed enabled.
142 if (propName.size() > 0 && propValue.size() > 0) {
143 // if property set & equal to value, then include overlay - otherwise skip
144 if (!check_property(propName, propValue)) {
145 return NO_OVERLAY_TAG;
146 }
147 }
148
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900149 if (target == String16(target_package_name)) {
150 return priority;
151 }
152 return NO_OVERLAY_TAG;
153 }
154
155 int parse_manifest(const void *data, size_t size, const char *target_package_name)
156 {
157 ResXMLTree parser;
158 parser.setTo(data, size);
159 if (parser.getError() != NO_ERROR) {
160 ALOGD("%s failed to init xml parser, error=0x%08x\n", __FUNCTION__, parser.getError());
161 return -1;
162 }
163
164 ResXMLParser::event_code_t type;
Jaekyun Seok04342892017-03-02 15:24:19 +0900165 bool is_static_overlay = false;
166 int priority = NO_OVERLAY_TAG;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900167 do {
168 type = parser.next();
169 if (type == ResXMLParser::START_TAG) {
170 size_t len;
171 String16 tag(parser.getElementName(&len));
Todd Leed5566c62017-03-16 14:00:52 -0700172 if (tag == String16("overlay")) {
Jaekyun Seok04342892017-03-02 15:24:19 +0900173 priority = parse_overlay_tag(parser, target_package_name, &is_static_overlay);
174 break;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900175 }
176 }
177 } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT);
178
Todd Leed5566c62017-03-16 14:00:52 -0700179 if (is_static_overlay) {
Jaekyun Seok04342892017-03-02 15:24:19 +0900180 return priority;
181 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900182 return NO_OVERLAY_TAG;
183 }
184
185 int parse_apk(const char *path, const char *target_package_name)
186 {
187 std::unique_ptr<ZipFileRO> zip(ZipFileRO::open(path));
188 if (zip.get() == NULL) {
189 ALOGW("%s: failed to open zip %s\n", __FUNCTION__, path);
190 return -1;
191 }
192 ZipEntryRO entry;
193 if ((entry = zip->findEntryByName("AndroidManifest.xml")) == NULL) {
194 ALOGW("%s: failed to find entry AndroidManifest.xml\n", __FUNCTION__);
195 return -1;
196 }
197 uint32_t uncompLen = 0;
198 uint16_t method;
199 if (!zip->getEntryInfo(entry, &method, &uncompLen, NULL, NULL, NULL, NULL)) {
200 ALOGW("%s: failed to read entry info\n", __FUNCTION__);
201 return -1;
202 }
203 if (method != ZipFileRO::kCompressDeflated) {
204 ALOGW("%s: cannot handle zip compression method %" PRIu16 "\n", __FUNCTION__, method);
205 return -1;
206 }
207 FileMap *dataMap = zip->createEntryFileMap(entry);
208 if (dataMap == NULL) {
209 ALOGW("%s: failed to create FileMap\n", __FUNCTION__);
210 return -1;
211 }
212 char *buf = new char[uncompLen];
213 if (NULL == buf) {
214 ALOGW("%s: failed to allocate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
215 delete dataMap;
216 return -1;
217 }
218 StreamingZipInflater inflater(dataMap, uncompLen);
219 if (inflater.read(buf, uncompLen) < 0) {
220 ALOGW("%s: failed to inflate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
221 delete[] buf;
222 delete dataMap;
223 return -1;
224 }
225
226 int priority = parse_manifest(buf, static_cast<size_t>(uncompLen), target_package_name);
227 delete[] buf;
228 delete dataMap;
229 return priority;
230 }
231}
232
233int idmap_scan(const char *target_package_name, const char *target_apk_path,
234 const char *idmap_dir, const android::Vector<const char *> *overlay_dirs)
235{
236 String8 filename = String8(idmap_dir);
237 filename.appendPath("overlays.list");
238
239 SortedVector<Overlay> overlayVector;
240 const size_t N = overlay_dirs->size();
241 for (size_t i = 0; i < N; ++i) {
242 const char *overlay_dir = overlay_dirs->itemAt(i);
243 DIR *dir = opendir(overlay_dir);
244 if (dir == NULL) {
245 return EXIT_FAILURE;
246 }
247
248 struct dirent *dirent;
249 while ((dirent = readdir(dir)) != NULL) {
250 struct stat st;
251 char overlay_apk_path[PATH_MAX + 1];
252 snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
253 if (stat(overlay_apk_path, &st) < 0) {
254 continue;
255 }
256 if (!S_ISREG(st.st_mode)) {
257 continue;
258 }
259
260 int priority = parse_apk(overlay_apk_path, target_package_name);
261 if (priority < 0) {
262 continue;
263 }
264
265 String8 idmap_path(idmap_dir);
266 idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
267 idmap_path.append("@idmap");
268
269 if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
270 ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
271 target_apk_path, overlay_apk_path, idmap_path.string());
272 continue;
273 }
274
275 Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
276 overlayVector.add(overlay);
277 }
278
279 closedir(dir);
280 }
281
282 if (!writePackagesList(filename.string(), overlayVector)) {
283 return EXIT_FAILURE;
284 }
285
286 return EXIT_SUCCESS;
287}
288