Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c14f0ad authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Gerrit Code Review
Browse files

Merge "Runtime resource overlay, iteration 2"

parents 340aa8cb 63568b14
Loading
Loading
Loading
Loading
+118 −10
Original line number Diff line number Diff line
@@ -618,14 +618,11 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
    ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
}

static int wait_dexopt(pid_t pid, const char* apk_path)
static int wait_child(pid_t pid)
{
    int status;
    pid_t got_pid;

    /*
     * Wait for the optimization process to finish.
     */
    while (1) {
        got_pid = waitpid(pid, &status, 0);
        if (got_pid == -1 && errno == EINTR) {
@@ -641,11 +638,8 @@ static int wait_dexopt(pid_t pid, const char* apk_path)
    }

    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
        ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
        return 0;
    } else {
        ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
            apk_path, status);
        return status;      /* always nonzero */
    }
}
@@ -747,9 +741,11 @@ int dexopt(const char *apk_path, uid_t uid, int is_public)
        }
        exit(68);   /* only get here on exec failure */
    } else {
        res = wait_dexopt(pid, apk_path);
        if (res != 0) {
            ALOGE("dexopt in='%s' out='%s' res=%d\n", apk_path, out_path, res);
        res = wait_child(pid);
        if (res == 0) {
            ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
        } else {
            ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", apk_path, res);
            goto fail;
        }
    }
@@ -1103,3 +1099,115 @@ out:

    return rc;
}

static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
{
    static const char *IDMAP_BIN = "/system/bin/idmap";
    static const size_t MAX_INT_LEN = 32;
    char idmap_str[MAX_INT_LEN];

    snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd);

    execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL);
    ALOGE("execl(%s) failed: %s\n", IDMAP_BIN, strerror(errno));
}

// Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix)
// eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
static int flatten_path(const char *prefix, const char *suffix,
        const char *overlay_path, char *idmap_path, size_t N)
{
    if (overlay_path == NULL || idmap_path == NULL) {
        return -1;
    }
    const size_t len_overlay_path = strlen(overlay_path);
    // will access overlay_path + 1 further below; requires absolute path
    if (len_overlay_path < 2 || *overlay_path != '/') {
        return -1;
    }
    const size_t len_idmap_root = strlen(prefix);
    const size_t len_suffix = strlen(suffix);
    if (SIZE_MAX - len_idmap_root < len_overlay_path ||
            SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) {
        // additions below would cause overflow
        return -1;
    }
    if (N < len_idmap_root + len_overlay_path + len_suffix) {
        return -1;
    }
    memset(idmap_path, 0, N);
    snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix);
    char *ch = idmap_path + len_idmap_root;
    while (*ch != '\0') {
        if (*ch == '/') {
            *ch = '@';
        }
        ++ch;
    }
    return 0;
}

int idmap(const char *target_apk, const char *overlay_apk, uid_t uid)
{
    ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);

    int idmap_fd = -1;
    char idmap_path[PATH_MAX];

    if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk,
                idmap_path, sizeof(idmap_path)) == -1) {
        ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk);
        goto fail;
    }

    unlink(idmap_path);
    idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644);
    if (idmap_fd < 0) {
        ALOGE("idmap cannot open '%s' for output: %s\n", idmap_path, strerror(errno));
        goto fail;
    }
    if (fchown(idmap_fd, AID_SYSTEM, uid) < 0) {
        ALOGE("idmap cannot chown '%s'\n", idmap_path);
        goto fail;
    }
    if (fchmod(idmap_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
        ALOGE("idmap cannot chmod '%s'\n", idmap_path);
        goto fail;
    }

    pid_t pid;
    pid = fork();
    if (pid == 0) {
        /* child -- drop privileges before continuing */
        if (setgid(uid) != 0) {
            ALOGE("setgid(%d) failed during idmap\n", uid);
            exit(1);
        }
        if (setuid(uid) != 0) {
            ALOGE("setuid(%d) failed during idmap\n", uid);
            exit(1);
        }
        if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) {
            ALOGE("flock(%s) failed during idmap: %s\n", idmap_path, strerror(errno));
            exit(1);
        }

        run_idmap(target_apk, overlay_apk, idmap_fd);
        exit(1); /* only if exec call to idmap failed */
    } else {
        int status = wait_child(pid);
        if (status != 0) {
            ALOGE("idmap failed, status=0x%04x\n", status);
            goto fail;
        }
    }

    close(idmap_fd);
    return 0;
fail:
    if (idmap_fd >= 0) {
        close(idmap_fd);
        unlink(idmap_path);
    }
    return -1;
}
+7 −0
Original line number Diff line number Diff line
@@ -124,6 +124,11 @@ static int do_linklib(char **arg, char reply[REPLY_MAX])
    return linklib(arg[0], arg[1], atoi(arg[2]));
}

static int do_idmap(char **arg, char reply[REPLY_MAX])
{
    return idmap(arg[0], arg[1], atoi(arg[2]));
}

struct cmdinfo {
    const char *name;
    unsigned numargs;
@@ -147,6 +152,7 @@ struct cmdinfo cmds[] = {
    { "linklib",              3, do_linklib },
    { "mkuserdata",           4, do_mk_user_data },
    { "rmuser",               1, do_rm_user },
    { "idmap",                3, do_idmap },
};

static int readx(int s, void *_buf, int count)
@@ -515,6 +521,7 @@ static void drop_privileges() {
    capdata[CAP_TO_INDEX(CAP_CHOWN)].permitted        |= CAP_TO_MASK(CAP_CHOWN);
    capdata[CAP_TO_INDEX(CAP_SETUID)].permitted       |= CAP_TO_MASK(CAP_SETUID);
    capdata[CAP_TO_INDEX(CAP_SETGID)].permitted       |= CAP_TO_MASK(CAP_SETGID);
    capdata[CAP_TO_INDEX(CAP_FOWNER)].permitted       |= CAP_TO_MASK(CAP_FOWNER);

    capdata[0].effective = capdata[0].permitted;
    capdata[1].effective = capdata[1].permitted;
+4 −0
Original line number Diff line number Diff line
@@ -75,6 +75,9 @@

#define UPDATE_COMMANDS_DIR_PREFIX  "/system/etc/updatecmds/"

#define IDMAP_PREFIX           "/data/resource-cache/"
#define IDMAP_SUFFIX           "@idmap"

#define PKG_NAME_MAX  128   /* largest allowed package name */
#define PKG_PATH_MAX  256   /* max size of any path we use */

@@ -207,3 +210,4 @@ int free_cache(int64_t free_size);
int dexopt(const char *apk_path, uid_t uid, int is_public);
int movefiles();
int linklib(const char* target, const char* source, int userId);
int idmap(const char *target_path, const char *overlay_path, uid_t uid);