android 调用 dexopt 的位置
来源:互联网 发布:巨人网络招聘2017 编辑:程序博客网 时间:2024/05/02 06:46
dexopt 是 android dalvik 虚拟机使用的优化程序,它负责把dex文件优化成odex。
位置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
函数execute 函数会调用
transaction
函数private int execute(String cmd) { String res = transaction(cmd); try { return Integer.parseInt(res); } catch (NumberFormatException ex) { return -1; }}
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"; }}
/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;}
当它收到消息后它会调用 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
函数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
函数,并等待那个进程结束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
- android 调用 dexopt 的位置
- [Android]Dalvik的BOOTCLASSPATH和dexopt流程
- use Android dexopt optimize all apks
- dexopt 的验证及优化过程
- Dalvik的BOOTCLASSPATH和dexopt流程
- android 调用系统的位置与安全(GPS)页面
- Android 开机震动的调用位置以及打开关闭方法
- 昨天遇到个dexopt失败的奇怪问题,记录一下
- 调用Android位置服务获取当前坐标
- Android setContentView的位置
- Android的位置服务
- 位置服务及GPS定位的调用
- 通过代码查找调用类的位置
- 函数调用子函数,注意子函数的位置
- dexopt魔数验证
- Android对话框的显示位置
- android应用程序的安装位置
- android AlertDialog 的位置问题
- kmp算法
- wpf 程序异常捕获,而不崩溃退出
- static_cast、dynamic_cast、const_cast和reinterpret_cast总结
- hidesBottomBarWhenPushed导航栏右上角黑块
- UITableViewCell点击时背景颜色
- android 调用 dexopt 的位置
- vim工具链环境搭建
- runtime API
- 控制摄像头拍照(一)
- TTL、CMOS、LVTTL、LVCMOS、LVDS
- spring 整合redis
- swift自学笔记(七)(可选类型、隐式解包、可选绑定)
- Java 中System里getProperty 方法获得系统参数
- php扩展安装