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