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