Home | History | Annotate | Download | only in idmap
      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 {
     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             // 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 
     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 
     62     String8 flatten_path(const char *path)
     63     {
     64         String16 tmp(path);
     65         tmp.replaceAll('/', '@');
     66         return String8(tmp);
     67     }
     68 
     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 
     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 
    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 
    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