1 #include <dirent.h>
2 #include <inttypes.h>
3 #include <sys/stat.h>
4 
5 #include "idmap.h"
6 
7 #include <memory>
8 #include <androidfw/ResourceTypes.h>
9 #include <androidfw/StreamingZipInflater.h>
10 #include <androidfw/ZipFileRO.h>
11 #include <private/android_filesystem_config.h> // for AID_SYSTEM
12 #include <utils/SortedVector.h>
13 #include <utils/String16.h>
14 #include <utils/String8.h>
15 
16 #define NO_OVERLAY_TAG (-1000)
17 
18 using namespace android;
19 
20 namespace {
21     struct Overlay {
Overlay__anon03d266df0111::Overlay22         Overlay() {}
Overlay__anon03d266df0111::Overlay23         Overlay(const String8& a, const String8& i, int p) :
24             apk_path(a), idmap_path(i), priority(p) {}
25 
operator <__anon03d266df0111::Overlay26         bool operator<(Overlay const& rhs) const
27         {
28             return rhs.priority > priority;
29         }
30 
31         String8 apk_path;
32         String8 idmap_path;
33         int priority;
34     };
35 
writePackagesList(const char * filename,const SortedVector<Overlay> & overlayVector)36     bool writePackagesList(const char *filename, const SortedVector<Overlay>& overlayVector)
37     {
38         FILE* fout = fopen(filename, "w");
39         if (fout == NULL) {
40             return false;
41         }
42 
43         for (size_t i = 0; i < overlayVector.size(); ++i) {
44             const Overlay& overlay = overlayVector[i];
45             fprintf(fout, "%s %s\n", overlay.apk_path.string(), overlay.idmap_path.string());
46         }
47 
48         fclose(fout);
49 
50         // Make file world readable since Zygote (running as root) will read
51         // it when creating the initial AssetManger object
52         const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 0644
53         if (chmod(filename, mode) == -1) {
54             unlink(filename);
55             return false;
56         }
57 
58         return true;
59     }
60 
flatten_path(const char * path)61     String8 flatten_path(const char *path)
62     {
63         String16 tmp(path);
64         tmp.replaceAll('/', '@');
65         return String8(tmp);
66     }
67 
parse_overlay_tag(const ResXMLTree & parser,const char * target_package_name)68     int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name)
69     {
70         const size_t N = parser.getAttributeCount();
71         String16 target;
72         int priority = -1;
73         for (size_t i = 0; i < N; ++i) {
74             size_t len;
75             String16 key(parser.getAttributeName(i, &len));
76             if (key == String16("targetPackage")) {
77                 const char16_t *p = parser.getAttributeStringValue(i, &len);
78                 if (p != NULL) {
79                     target = String16(p, len);
80                 }
81             } else if (key == String16("priority")) {
82                 Res_value v;
83                 if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) {
84                     priority = v.data;
85                     if (priority < 0 || priority > 9999) {
86                         return -1;
87                     }
88                 }
89             }
90         }
91         if (target == String16(target_package_name)) {
92             return priority;
93         }
94         return NO_OVERLAY_TAG;
95     }
96 
parse_manifest(const void * data,size_t size,const char * target_package_name)97     int parse_manifest(const void *data, size_t size, const char *target_package_name)
98     {
99         ResXMLTree parser;
100         parser.setTo(data, size);
101         if (parser.getError() != NO_ERROR) {
102             ALOGD("%s failed to init xml parser, error=0x%08x\n", __FUNCTION__, parser.getError());
103             return -1;
104         }
105 
106         ResXMLParser::event_code_t type;
107         do {
108             type = parser.next();
109             if (type == ResXMLParser::START_TAG) {
110                 size_t len;
111                 String16 tag(parser.getElementName(&len));
112                 if (tag == String16("overlay")) {
113                     return parse_overlay_tag(parser, target_package_name);
114                 }
115             }
116         } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT);
117 
118         return NO_OVERLAY_TAG;
119     }
120 
parse_apk(const char * path,const char * target_package_name)121     int parse_apk(const char *path, const char *target_package_name)
122     {
123         std::unique_ptr<ZipFileRO> zip(ZipFileRO::open(path));
124         if (zip.get() == NULL) {
125             ALOGW("%s: failed to open zip %s\n", __FUNCTION__, path);
126             return -1;
127         }
128         ZipEntryRO entry;
129         if ((entry = zip->findEntryByName("AndroidManifest.xml")) == NULL) {
130             ALOGW("%s: failed to find entry AndroidManifest.xml\n", __FUNCTION__);
131             return -1;
132         }
133         uint32_t uncompLen = 0;
134         uint16_t method;
135         if (!zip->getEntryInfo(entry, &method, &uncompLen, NULL, NULL, NULL, NULL)) {
136             ALOGW("%s: failed to read entry info\n", __FUNCTION__);
137             return -1;
138         }
139         if (method != ZipFileRO::kCompressDeflated) {
140             ALOGW("%s: cannot handle zip compression method %" PRIu16 "\n", __FUNCTION__, method);
141             return -1;
142         }
143         FileMap *dataMap = zip->createEntryFileMap(entry);
144         if (dataMap == NULL) {
145             ALOGW("%s: failed to create FileMap\n", __FUNCTION__);
146             return -1;
147         }
148         char *buf = new char[uncompLen];
149         if (NULL == buf) {
150             ALOGW("%s: failed to allocate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
151             delete dataMap;
152             return -1;
153         }
154         StreamingZipInflater inflater(dataMap, uncompLen);
155         if (inflater.read(buf, uncompLen) < 0) {
156             ALOGW("%s: failed to inflate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
157             delete[] buf;
158             delete dataMap;
159             return -1;
160         }
161 
162         int priority = parse_manifest(buf, static_cast<size_t>(uncompLen), target_package_name);
163         delete[] buf;
164         delete dataMap;
165         return priority;
166     }
167 }
168 
idmap_scan(const char * target_package_name,const char * target_apk_path,const char * idmap_dir,const android::Vector<const char * > * overlay_dirs)169 int idmap_scan(const char *target_package_name, const char *target_apk_path,
170         const char *idmap_dir, const android::Vector<const char *> *overlay_dirs)
171 {
172     String8 filename = String8(idmap_dir);
173     filename.appendPath("overlays.list");
174     if (unlink(filename.string()) != 0 && errno != ENOENT) {
175         return EXIT_FAILURE;
176     }
177 
178     SortedVector<Overlay> overlayVector;
179     const size_t N = overlay_dirs->size();
180     for (size_t i = 0; i < N; ++i) {
181         const char *overlay_dir = overlay_dirs->itemAt(i);
182         DIR *dir = opendir(overlay_dir);
183         if (dir == NULL) {
184             return EXIT_FAILURE;
185         }
186 
187         struct dirent *dirent;
188         while ((dirent = readdir(dir)) != NULL) {
189             struct stat st;
190             char overlay_apk_path[PATH_MAX + 1];
191             snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
192             if (stat(overlay_apk_path, &st) < 0) {
193                 continue;
194             }
195             if (!S_ISREG(st.st_mode)) {
196                 continue;
197             }
198 
199             int priority = parse_apk(overlay_apk_path, target_package_name);
200             if (priority < 0) {
201                 continue;
202             }
203 
204             String8 idmap_path(idmap_dir);
205             idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
206             idmap_path.append("@idmap");
207 
208             if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
209                 ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
210                         target_apk_path, overlay_apk_path, idmap_path.string());
211                 continue;
212             }
213 
214             Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
215             overlayVector.add(overlay);
216         }
217 
218         closedir(dir);
219     }
220 
221     if (!writePackagesList(filename.string(), overlayVector)) {
222         return EXIT_FAILURE;
223     }
224 
225     return EXIT_SUCCESS;
226 }
227