OSDN Git Service

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