Home | History | Annotate | Download | only in idmap
      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 }
    246