1 #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>
12 #include <cutils/jstring.h>
13 #include <cutils/properties.h>
14 #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 
21 using namespace android;
22 
23 namespace {
24     struct Overlay {
Overlay__anon03d266df0111::Overlay25         Overlay() {}
Overlay__anon03d266df0111::Overlay26         Overlay(const String8& a, const String8& i, int p) :
27             apk_path(a), idmap_path(i), priority(p) {}
28 
operator <__anon03d266df0111::Overlay29         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 
writePackagesList(const char * filename,const SortedVector<Overlay> & overlayVector)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 
flatten_path(const char * path)79     String8 flatten_path(const char *path)
80     {
81         String16 tmp(path);
82         tmp.replaceAll('/', '@');
83         return String8(tmp);
84     }
85 
check_property(String16 property,String16 value)86     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 
parse_overlay_tag(const ResXMLTree & parser,const char * target_package_name,bool * is_static_overlay)98     int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name,
99             bool* is_static_overlay)
100     {
101         const size_t N = parser.getAttributeCount();
102         String16 target;
103         int priority = -1;
104         String16 propName = String16();
105         String16 propValue = String16();
106         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                 }
122             } 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                 }
127             } 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                 }
137             }
138         }
139 
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 
149         if (target == String16(target_package_name)) {
150             return priority;
151         }
152         return NO_OVERLAY_TAG;
153     }
154 
parse_manifest(const void * data,size_t size,const char * target_package_name)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;
165         bool is_static_overlay = false;
166         int priority = NO_OVERLAY_TAG;
167         do {
168             type = parser.next();
169             if (type == ResXMLParser::START_TAG) {
170                 size_t len;
171                 String16 tag(parser.getElementName(&len));
172                 if (tag == String16("overlay")) {
173                     priority = parse_overlay_tag(parser, target_package_name, &is_static_overlay);
174                     break;
175                 }
176             }
177         } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT);
178 
179         if (is_static_overlay) {
180             return priority;
181         }
182         return NO_OVERLAY_TAG;
183     }
184 
parse_apk(const char * path,const char * target_package_name)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 
idmap_scan(const char * target_package_name,const char * target_apk_path,const char * idmap_dir,const android::Vector<const char * > * overlay_dirs)233 int 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 
289