OSDN Git Service

am af60e56b: Revert "DO NOT MERGE Fix extraneous allocation and copying"
[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(data, size);
123         if (parser.getError() != NO_ERROR) {
124             ALOGD("%s failed to init xml parser, error=0x%08x\n", __FUNCTION__, parser.getError());
125             return -1;
126         }
127
128         ResXMLParser::event_code_t type;
129         do {
130             type = parser.next();
131             if (type == ResXMLParser::START_TAG) {
132                 size_t len;
133                 String16 tag(parser.getElementName(&len));
134                 if (tag == String16("overlay")) {
135                     return parse_overlay_tag(parser, target_package_name);
136                 }
137             }
138         } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT);
139
140         return NO_OVERLAY_TAG;
141     }
142
143     int parse_apk(const char *path, const char *target_package_name)
144     {
145         UniquePtr<ZipFileRO> zip(ZipFileRO::open(path));
146         if (zip.get() == NULL) {
147             ALOGW("%s: failed to open zip %s\n", __FUNCTION__, path);
148             return -1;
149         }
150         ZipEntryRO entry;
151         if ((entry = zip->findEntryByName("AndroidManifest.xml")) == NULL) {
152             ALOGW("%s: failed to find entry AndroidManifest.xml\n", __FUNCTION__);
153             return -1;
154         }
155         size_t uncompLen = 0;
156         int method;
157         if (!zip->getEntryInfo(entry, &method, &uncompLen, NULL, NULL, NULL, NULL)) {
158             ALOGW("%s: failed to read entry info\n", __FUNCTION__);
159             return -1;
160         }
161         if (method != ZipFileRO::kCompressDeflated) {
162             ALOGW("%s: cannot handle zip compression method %d\n", __FUNCTION__, method);
163             return -1;
164         }
165         FileMap *dataMap = zip->createEntryFileMap(entry);
166         if (!dataMap) {
167             ALOGW("%s: failed to create FileMap\n", __FUNCTION__);
168             return -1;
169         }
170         char *buf = new char[uncompLen];
171         if (NULL == buf) {
172             ALOGW("%s: failed to allocate %d byte\n", __FUNCTION__, uncompLen);
173             dataMap->release();
174             return -1;
175         }
176         StreamingZipInflater inflater(dataMap, uncompLen);
177         if (inflater.read(buf, uncompLen) < 0) {
178             ALOGW("%s: failed to inflate %d byte\n", __FUNCTION__, uncompLen);
179             delete[] buf;
180             dataMap->release();
181             return -1;
182         }
183
184         int priority = parse_manifest(buf, uncompLen, target_package_name);
185         delete[] buf;
186         dataMap->release();
187         return priority;
188     }
189 }
190
191 int idmap_scan(const char *overlay_dir, const char *target_package_name,
192         const char *target_apk_path, const char *idmap_dir)
193 {
194     String8 filename = String8(idmap_dir);
195     filename.appendPath("overlays.list");
196     if (unlink(filename.string()) != 0 && errno != ENOENT) {
197         return EXIT_FAILURE;
198     }
199
200     DIR *dir = opendir(overlay_dir);
201     if (dir == NULL) {
202         return EXIT_FAILURE;
203     }
204
205     SortedVector<Overlay> overlayVector;
206     struct dirent *dirent;
207     while ((dirent = readdir(dir)) != NULL) {
208         struct stat st;
209         char overlay_apk_path[PATH_MAX + 1];
210         snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
211         if (stat(overlay_apk_path, &st) < 0) {
212             continue;
213         }
214         if (!S_ISREG(st.st_mode)) {
215             continue;
216         }
217
218         int priority = parse_apk(overlay_apk_path, target_package_name);
219         if (priority < 0) {
220             continue;
221         }
222
223         String8 idmap_path(idmap_dir);
224         idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
225         idmap_path.append("@idmap");
226
227         if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
228             ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
229                     target_apk_path, overlay_apk_path, idmap_path.string());
230             continue;
231         }
232
233         Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
234         overlayVector.add(overlay);
235     }
236
237     closedir(dir);
238
239     if (!writePackagesList(filename.string(), overlayVector)) {
240         return EXIT_FAILURE;
241     }
242
243     return EXIT_SUCCESS;
244 }