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
18using namespace android;
19
20namespace {
21    struct Overlay {
22        Overlay() {}
23        Overlay(const String8& a, const String8& i, int p) :
24            apk_path(a), idmap_path(i), priority(p) {}
25
26        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
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
61    String8 flatten_path(const char *path)
62    {
63        String16 tmp(path);
64        tmp.replaceAll('/', '@');
65        return String8(tmp);
66    }
67
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
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
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
169int 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