android 调用 dexopt 的位置

来源:互联网 发布:巨人网络招聘2017 编辑:程序博客网 时间:2024/05/02 06:46

dexopt 是 android dalvik 虚拟机使用的优化程序,它负责把dex文件优化成odex。


位置1 安装的时候调用

  1. PackageManagerService 中的 Installer.java 里执行 dexopt 方法

    public int dexopt(String apkPath, int uid, boolean isPublic)     {    StringBuilder builder = new StringBuilder("dexopt");    builder.append(' ');    builder.append(apkPath);    builder.append(' ');    builder.append(uid);    builder.append(isPublic ? " 1" : " 0");    return execute(builder.toString());}

    其中会调用 execute 函数

  2. execute 函数会调用 transaction 函数

    private int execute(String cmd) {    String res = transaction(cmd);    try {        return Integer.parseInt(res);    } catch (NumberFormatException ex) {        return -1;    }}
  3. transaction 函数最终通过socket接口向 /system/bin/installd 进程发送安装消息

    private synchronized String transaction(String cmd) {    if (!connect()) {        Slog.e(TAG, "connection failed");        return "-1";    }    if (!writeCommand(cmd)) {        /*         * If installd died and restarted in the background (unlikely but         * possible) we'll fail on the next write (this one). Try to         * reconnect and write the command one more time before giving up.         */        Slog.e(TAG, "write command failed? reconnect!");        if (!connect() || !writeCommand(cmd)) {            return "-1";        }    }    if (LOCAL_DEBUG) {        Slog.i(TAG, "send: '" + cmd + "'");    }    if (readReply()) {        String s = new String(buf, 0, buflen);        if (LOCAL_DEBUG) {            Slog.i(TAG, "recv: '" + s + "'");        }        return s;    } else {        if (LOCAL_DEBUG) {            Slog.i(TAG, "fail");        }        return "-1";    }}
  4. /system/bin/installd 进程由init.rc创建

    service installd /system/bin/installd    class main    socket installd stream 600 system system

    它启动后会监听一个本地的socket端口,供其他程序调用
    并且它在main函数中循环监听该端口

    int main(const int argc, const char *argv[]) {    char buf[BUFFER_MAX];    struct sockaddr addr;    socklen_t alen;    int lsocket, s, count;    if (initialize_globals() < 0) {        LOGE("Could not initialize globals; exiting.\n");        exit(1);    }    if (initialize_directories() < 0) {        LOGE("Could not create directories; exiting.\n");        exit(1);    }    lsocket = android_get_control_socket(SOCKET_PATH);    if (lsocket < 0) {        LOGE("Failed to get socket from environment: %s\n", strerror(errno));        exit(1);    }    if (listen(lsocket, 5)) {        LOGE("Listen on socket failed: %s\n",         strerror(errno));        exit(1);    }    fcntl(lsocket, F_SETFD, FD_CLOEXEC);    for (;;) {        alen = sizeof(addr);        s = accept(lsocket, &addr, &alen);        if (s < 0) {            LOGE("Accept failed: %s\n", strerror(errno));            continue;        }        fcntl(s, F_SETFD, FD_CLOEXEC);        LOGI("new connection\n");        for (;;) {            unsigned short count;            if (readx(s, &count, sizeof(count))) {                LOGE("failed to read size\n");                break;            }            if ((count < 1) || (count >= BUFFER_MAX)) {                LOGE("invalid size %d\n", count);                break;            }            if (readx(s, buf, count)) {                LOGE("failed to read command\n");                break;            }            buf[count] = 0;            if (execute(s, buf)) break;        }        LOGI("closing connection\n");        close(s);    }    return 0;}
  5. 当它收到消息后它会调用 execute 函数

    static int execute(int s, char cmd[BUFFER_MAX]){    char reply[REPLY_MAX];    char *arg[TOKEN_MAX+1];    unsigned i;    unsigned n = 0;    unsigned short count;    int ret = -1;//    LOGI("execute('%s')\n", cmd);        /* default reply is "" */    reply[0] = 0;        /* n is number of args (not counting arg[0]) */    arg[0] = cmd;    while (*cmd) {        if (isspace(*cmd)) {            *cmd++ = 0;            n++;            arg[n] = cmd;            if (n == TOKEN_MAX) {                LOGE("too many arguments\n");                goto done;            }        }        cmd++;    }    for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {        if (!strcmp(cmds[i].name,arg[0])) {            if (n != cmds[i].numargs) {                LOGE("%s requires %d arguments (%d given)\n",                     cmds[i].name, cmds[i].numargs, n);            } else {                ret = cmds[i].func(arg + 1, reply);            }            goto done;        }    }    LOGE("unsupported command '%s'\n", arg[0]);done:    if (reply[0]) {        n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply);    } else {        n = snprintf(cmd, BUFFER_MAX, "%d", ret);    }    if (n > BUFFER_MAX) n = BUFFER_MAX;    count = n;//    LOGI("reply: '%s'\n", cmd);    if (writex(s, &count, sizeof(count))) return -1;    if (writex(s, cmd, count)) return -1;    return 0;}

    这个函数会从这个数组里找到这个消息对应的处理函数

    struct cmdinfo cmds[] = {    { "ping",                 0, do_ping },    { "install",              3, do_install },    { "dexopt",               3, do_dexopt },    { "movedex",              2, do_move_dex },    { "rmdex",                1, do_rm_dex },    { "remove",               2, do_remove },    { "rename",               2, do_rename },    { "freecache",            1, do_free_cache },    { "rmcache",              1, do_rm_cache },    { "protect",              2, do_protect },    { "getsize",              4, do_get_size },    { "rmuserdata",           2, do_rm_user_data },    { "movefiles",            0, do_movefiles },    { "linklib",              2, do_linklib },    { "unlinklib",            1, do_unlinklib },    { "mkuserdata",           3, do_mk_user_data },    { "rmuser",               1, do_rm_user },};

    可以看到 dexopt 对应的是 do_dexopt 函数

  6. do_dexopt 会调用 dexopt 函数

    int dexopt(const char *apk_path, uid_t uid, int is_public){    struct utimbuf ut;    struct stat apk_stat, dex_stat;    char dex_path[PKG_PATH_MAX];    char dexopt_flags[PROPERTY_VALUE_MAX];    char *end;    int res, zip_fd=-1, odex_fd=-1;        /* Before anything else: is there a .odex file?  If so, we have         * pre-optimized the apk and there is nothing to do here.         */    if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {        return -1;    }    /* platform-specific flags affecting optimization and verification */    property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");    strcpy(dex_path, apk_path);    end = strrchr(dex_path, '.');    if (end != NULL) {        strcpy(end, ".odex");        if (stat(dex_path, &dex_stat) == 0) {            return 0;        }    }    if (create_cache_path(dex_path, apk_path)) {        return -1;    }    memset(&apk_stat, 0, sizeof(apk_stat));    stat(apk_path, &apk_stat);    zip_fd = open(apk_path, O_RDONLY, 0);    if (zip_fd < 0) {        LOGE("dexopt cannot open '%s' for input\n", apk_path);        return -1;    }    unlink(dex_path);    odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);    if (odex_fd < 0) {        LOGE("dexopt cannot open '%s' for output\n", dex_path);        goto fail;    }    if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {        LOGE("dexopt cannot chown '%s'\n", dex_path);        goto fail;    }    if (fchmod(odex_fd,               S_IRUSR|S_IWUSR|S_IRGRP |               (is_public ? S_IROTH : 0)) < 0) {        LOGE("dexopt cannot chmod '%s'\n", dex_path);        goto fail;    }    LOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);    pid_t pid;    pid = fork();    if (pid == 0) {        /* child -- drop privileges before continuing */        if (setgid(uid) != 0) {            LOGE("setgid(%d) failed during dexopt\n", uid);            exit(64);        }        if (setuid(uid) != 0) {            LOGE("setuid(%d) during dexopt\n", uid);            exit(65);        }        if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {            LOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));            exit(66);        }        run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);        exit(67);   /* only get here on exec failure */    } else {        res = wait_dexopt(pid, apk_path);        if (res != 0) {            LOGE("dexopt failed on '%s' res = %d\n", dex_path, res);            goto fail;        }    }    ut.actime = apk_stat.st_atime;    ut.modtime = apk_stat.st_mtime;    utime(dex_path, &ut);    close(odex_fd);    close(zip_fd);    return 0;fail:    if (odex_fd >= 0) {        close(odex_fd);        unlink(dex_path);    }    if (zip_fd >= 0) {        close(zip_fd);    }    return -1;}

    这里 dexopt 会启动一个新进程去执行 run_dexopt 函数,并等待那个进程结束

  7. run_dexopt 会调用 /system/bin/dexopt命令

    static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,    const char* dexopt_flags){    static const char* DEX_OPT_BIN = "/system/bin/dexopt";    static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig    char zip_num[MAX_INT_LEN];    char odex_num[MAX_INT_LEN];    sprintf(zip_num, "%d", zip_fd);    sprintf(odex_num, "%d", odex_fd);    execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,        dexopt_flags, (char*) NULL);    LOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));}

位置2 在调用DexClassLoader时调用(未完待续)

0 0
原创粉丝点击