Home | History | Annotate | Download | only in idmap
      1 #include <dirent.h>
      2 #include <inttypes.h>
      3 #include <sys/file.h>
      4 #include <sys/stat.h>
      5 
      6 #include "idmap.h"
      7 
      8 #include <memory>
      9 #include <androidfw/ResourceTypes.h>
     10 #include <androidfw/StreamingZipInflater.h>
     11 #include <androidfw/ZipFileRO.h>
     12 #include <cutils/jstring.h>
     13 #include <cutils/properties.h>
     14 #include <private/android_filesystem_config.h> // for AID_SYSTEM
     15 #include <utils/SortedVector.h>
     16 #include <utils/String16.h>
     17 #include <utils/String8.h>
     18 
     19 #define NO_OVERLAY_TAG (-1000)
     20 
     21 using namespace android;
     22 
     23 namespace {
     24     struct Overlay {
     25         Overlay() {}
     26         Overlay(const String8& a, const String8& i, int p) :
     27             apk_path(a), idmap_path(i), priority(p) {}
     28 
     29         bool operator<(Overlay const& rhs) const
     30         {
     31             return rhs.priority > priority;
     32         }
     33 
     34         String8 apk_path;
     35         String8 idmap_path;
     36         int priority;
     37     };
     38 
     39     bool writePackagesList(const char *filename, const SortedVector<Overlay>& overlayVector)
     40     {
     41         // the file is opened for appending so that it doesn't get truncated
     42         // before we can guarantee mutual exclusion via the flock
     43         FILE* fout = fopen(filename, "a");
     44         if (fout == NULL) {
     45             return false;
     46         }
     47 
     48         if (TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_EX)) != 0) {
     49             fclose(fout);
     50             return false;
     51         }
     52 
     53         if (TEMP_FAILURE_RETRY(ftruncate(fileno(fout), 0)) != 0) {
     54             TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
     55             fclose(fout);
     56             return false;
     57         }
     58 
     59         for (size_t i = 0; i < overlayVector.size(); ++i) {
     60             const Overlay& overlay = overlayVector[i];
     61             fprintf(fout, "%s %s\n", overlay.apk_path.string(), overlay.idmap_path.string());
     62         }
     63 
     64         TEMP_FAILURE_RETRY(fflush(fout));
     65         TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
     66         fclose(fout);
     67 
     68         // Make file world readable since Zygote (running as root) will read
     69         // it when creating the initial AssetManger object
     70         const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 0644
     71         if (chmod(filename, mode) == -1) {
     72             unlink(filename);
     73             return false;
     74         }
     75 
     76         return true;
     77     }
     78 
     79     String8 flatten_path(const char *path)
     80     {
     81         String16 tmp(path);
     82         tmp.replaceAll('/', '@');
     83         return String8(tmp);
     84     }
     85 
     86     bool check_property(String16 property, String16 value) {
     87         const char *prop;
     88         const char *val;
     89 
     90         prop = strndup16to8(property.string(), property.size());
     91         char propBuf[PROPERTY_VALUE_MAX];
     92         property_get(prop, propBuf, NULL);
     93         val = strndup16to8(value.string(), value.size());
     94 
     95         return (strcmp(propBuf, val) == 0);
     96     }
     97 
     98     int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name,
     99             bool* is_static_overlay)
    100     {
    101         const size_t N = parser.getAttributeCount();
    102         String16 target;
    103         int priority = -1;
    104         String16 propName = String16();
    105         String16 propValue = String16();
    106         for (size_t i = 0; i < N; ++i) {
    107             size_t len;
    108             String16 key(parser.getAttributeName(i, &len));
    109             if (key == String16("targetPackage")) {
    110                 const char16_t *p = parser.getAttributeStringValue(i, &len);
    111                 if (p != NULL) {
    112                     target = String16(p, len);
    113                 }
    114             } else if (key == String16("priority")) {
    115                 Res_value v;
    116                 if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) {
    117                     priority = v.data;
    118                     if (priority < 0 || priority > 9999) {
    119                         return -1;
    120                     }
    121                 }
    122             } else if (key == String16("isStatic")) {
    123                 Res_value v;
    124                 if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) {
    125                     *is_static_overlay = (v.data != 0);
    126                 }
    127             } else if (key == String16("requiredSystemPropertyName")) {
    128                 const char16_t *p = parser.getAttributeStringValue(i, &len);
    129                 if (p != NULL) {
    130                     propName = String16(p, len);
    131                 }
    132             } else if (key == String16("requiredSystemPropertyValue")) {
    133                 const char16_t *p = parser.getAttributeStringValue(i, &len);
    134                 if (p != NULL) {
    135                     propValue = String16(p, len);
    136                 }
    137             }
    138         }
    139 
    140         // Note that conditional property enablement/exclusion only applies if
    141         // the attribute is present. In its absence, all overlays are presumed enabled.
    142         if (propName.size() > 0 && propValue.size() > 0) {
    143             // if property set & equal to value, then include overlay - otherwise skip
    144             if (!check_property(propName, propValue)) {
    145                 return NO_OVERLAY_TAG;
    146             }
    147         }
    148 
    149         if (target == String16(target_package_name)) {
    150             return priority;
    151         }
    152         return NO_OVERLAY_TAG;
    153     }
    154 
    155     int parse_manifest(const void *data, size_t size, const char *target_package_name)
    156     {
    157         ResXMLTree parser;
    158         parser.setTo(data, size);
    159         if (parser.getError() != NO_ERROR) {
    160             ALOGD("%s failed to init xml parser, error=0x%08x\n", __FUNCTION__, parser.getError());
    161             return -1;
    162         }
    163 
    164         ResXMLParser::event_code_t type;
    165         bool is_static_overlay = false;
    166         int priority = NO_OVERLAY_TAG;
    167         do {
    168             type = parser.next();
    169             if (type == ResXMLParser::START_TAG) {
    170                 size_t len;
    171                 String16 tag(parser.getElementName(&len));
    172                 if (tag == String16("overlay")) {
    173                     priority = parse_overlay_tag(parser, target_package_name, &is_static_overlay);
    174                     break;
    175                 }
    176             }
    177         } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT);
    178 
    179         if (is_static_overlay) {
    180             return priority;
    181         }
    182         return NO_OVERLAY_TAG;
    183     }
    184 
    185     int parse_apk(const char *path, const char *target_package_name)
    186     {
    187         std::unique_ptr<ZipFileRO> zip(ZipFileRO::open(path));
    188         if (zip.get() == NULL) {
    189             ALOGW("%s: failed to open zip %s\n", __FUNCTION__, path);
    190             return -1;
    191         }
    192         ZipEntryRO entry;
    193         if ((entry = zip->findEntryByName("AndroidManifest.xml")) == NULL) {
    194             ALOGW("%s: failed to find entry AndroidManifest.xml\n", __FUNCTION__);
    195             return -1;
    196         }
    197         uint32_t uncompLen = 0;
    198         uint16_t method;
    199         if (!zip->getEntryInfo(entry, &method, &uncompLen, NULL, NULL, NULL, NULL)) {
    200             ALOGW("%s: failed to read entry info\n", __FUNCTION__);
    201             return -1;
    202         }
    203         if (method != ZipFileRO::kCompressDeflated) {
    204             ALOGW("%s: cannot handle zip compression method %" PRIu16 "\n", __FUNCTION__, method);
    205             return -1;
    206         }
    207         FileMap *dataMap = zip->createEntryFileMap(entry);
    208         if (dataMap == NULL) {
    209             ALOGW("%s: failed to create FileMap\n", __FUNCTION__);
    210             return -1;
    211         }
    212         char *buf = new char[uncompLen];
    213         if (NULL == buf) {
    214             ALOGW("%s: failed to allocate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
    215             delete dataMap;
    216             return -1;
    217         }
    218         StreamingZipInflater inflater(dataMap, uncompLen);
    219         if (inflater.read(buf, uncompLen) < 0) {
    220             ALOGW("%s: failed to inflate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
    221             delete[] buf;
    222             delete dataMap;
    223             return -1;
    224         }
    225 
    226         int priority = parse_manifest(buf, static_cast<size_t>(uncompLen), target_package_name);
    227         delete[] buf;
    228         delete dataMap;
    229         return priority;
    230     }
    231 }
    232 
    233 int idmap_scan(const char *target_package_name, const char *target_apk_path,
    234         const char *idmap_dir, const android::Vector<const char *> *overlay_dirs)
    235 {
    236     String8 filename = String8(idmap_dir);
    237     filename.appendPath("overlays.list");
    238 
    239     SortedVector<Overlay> overlayVector;
    240     const size_t N = overlay_dirs->size();
    241     for (size_t i = 0; i < N; ++i) {
    242         const char *overlay_dir = overlay_dirs->itemAt(i);
    243         DIR *dir = opendir(overlay_dir);
    244         if (dir == NULL) {
    245             return EXIT_FAILURE;
    246         }
    247 
    248         struct dirent *dirent;
    249         while ((dirent = readdir(dir)) != NULL) {
    250             struct stat st;
    251             char overlay_apk_path[PATH_MAX + 1];
    252             snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
    253             if (stat(overlay_apk_path, &st) < 0) {
    254                 continue;
    255             }
    256             if (!S_ISREG(st.st_mode)) {
    257                 continue;
    258             }
    259 
    260             int priority = parse_apk(overlay_apk_path, target_package_name);
    261             if (priority < 0) {
    262                 continue;
    263             }
    264 
    265             String8 idmap_path(idmap_dir);
    266             idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
    267             idmap_path.append("@idmap");
    268 
    269             if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
    270                 ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
    271                         target_apk_path, overlay_apk_path, idmap_path.string());
    272                 continue;
    273             }
    274 
    275             Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
    276             overlayVector.add(overlay);
    277         }
    278 
    279         closedir(dir);
    280     }
    281 
    282     if (!writePackagesList(filename.string(), overlayVector)) {
    283         return EXIT_FAILURE;
    284     }
    285 
    286     return EXIT_SUCCESS;
    287 }
    288 
    289