如果你有这样的问题:
1.Dalvik和ART的区别
2.DEX在Dalvik转化为ODEX和ART中转化为ODEX的过程有上面区别
3.multidex在dalvik上起作用,ART上使用的也是multidex么(如果不是的话在application中写入multidex.install会对apk启动造成影响么)
如果你比较“懒”,,懒得看老罗的源码分析,,,长篇大论
请“简要”看完以下“简要”内容
一:Dalvik和ART的区别#
Dalvik: Dalvik是Google公司自己设计用于Android平台的Java虚拟机它可以支持已转换为 .dex(即Dalvik Executable)格式的Java应用程序的运行,.dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。执行的是字节码,它是依靠Just-In-Time (JIT)机制去解释字节码
ART:即Android Runtime,google为了替代Dalvik专门为Android研发的。Android KK为开发者推出,L版本正式上线。比替代品更高效省电,执行的是本地机器码(也就是linux的ELF文件格式),依靠Ahead-Of-Time (AOT)机制
二.在不同平台DEX转化为ODEX的过程#
简化流程如下:
这里参考的是
http://blog.csdn.net/luoshengyang/article/details/18006645
android安装过程源码分析:http://blog.csdn.net/luoshengyang/article/details/6747696
简单来说,就是Android系统通过PackageManagerService来安装APK,在安装的过程,PackageManagerService会通过另外一个类Installer的成员函数dexopt来对APK里面的dex字节码进行优化:
public final class Installer {
......
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());
}
......
}
这个函数定义在文件frameworks/base/services/java/com/android/server/pm/Installer.java中。Installer通过socket向守护进程installd发送一个dexopt请求,这个请求是由installd里面的函数dexopt来处理的。详细过程请移步Android ART运行时无缝替换Dalvik虚拟机的过程分析
int dexopt(const char *apk_path, uid_t uid, int is_public)
{
struct utimbuf ut;
struct stat apk_stat, dex_stat;
char out_path[PKG_PATH_MAX];
char dexopt_flags[PROPERTY_VALUE_MAX];
char persist_sys_dalvik_vm_lib[PROPERTY_VALUE_MAX];
char *end;
int res, zip_fd=-1, out_fd=-1;
......
/* The command to run depend ones the value of persist.sys.dalvik.vm.lib */
property_get("persist.sys.dalvik.vm.lib", persist_sys_dalvik_vm_lib, "libdvm.so");
/* Before anything else: is there a .odex file? If so, we have
* precompiled the apk and there is nothing to do here.
*/
sprintf(out_path, "%s%s", apk_path, ".odex");
if (stat(out_path, &dex_stat) == 0) {
return 0;
}
if (create_cache_path(out_path, apk_path)) {
return -1;
}
......
out_fd = open(out_path, O_RDWR | O_CREAT | O_EXCL, 0644);
......
pid_t pid;
pid = fork();
if (pid == 0) {
......
if (strncmp(persist_sys_dalvik_vm_lib, "libdvm", 6) == 0) {
run_dexopt(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
} else if (strncmp(persist_sys_dalvik_vm_lib, "libart", 6) == 0) {
run_dex2oat(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
} else {
exit(69); /* Unexpected persist.sys.dalvik.vm.lib value */
}
exit(68); /* only get here on exec failure */
}
......
}
……
static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
const char* output_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);
ALOGV("Running %s in=%s out=%s\n", DEX_OPT_BIN, input_file_name, output_file_name);
execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
dexopt_flags, (char*) NULL);
ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
}
static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
const char* output_file_name, const char* dexopt_flags)
{
static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN];
char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX];
char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN];
char oat_location_arg[strlen("--oat-name=") + PKG_PATH_MAX];
sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
sprintf(zip_location_arg, "--zip-location=%s", input_file_name);
sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);
execl(DEX2OAT_BIN, DEX2OAT_BIN,
zip_fd_arg, zip_location_arg,
oat_fd_arg, oat_location_arg,
(char*) NULL);
ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
}
函数定义在frameworks/native/cmds/installd/commands.c中 函数dexopt首先是读取系统属性persist.sys.dalvik.vm.lib的值,接着在/data/dalvik-cache目录中创建一个odex文件。这个odex文件就是作为dex文件优化后的输出文件。再接下来,函数dexopt通过fork来创建一个子进程。如果系统属性persist.sys.dalvik.vm.lib的值等于libdvm.so,那么该子进程就会调用函数run_dexopt来将dex文件优化成odex文件。另一方面,如果系统属性persist.sys.dalvik.vm.lib的值等于libart.so,那么该子进程就会调用函数run_dex2oat来将dex文件翻译成oat文件,实际上就是将dex字节码翻译成本地机器码,并且保存在一个oat文件中。
函数run_dexopt通过调用/system/bin/dexopt来对dex字节码进行优化,而函数run_dex2oat通过调用/system/bin/dex2oat来将dex字节码翻译成本地机器码。注意,无论是对dex字节码进行优化,还是将dex字节码翻译成本地机器码,最终得到的结果都是保存在相同名称的一个odex文件里面的,但是前者对应的是一个dey文件(表示这是一个优化过的dex),后者对应的是一个oat文件(实际上是一个自定义的elf文件,里面包含的都是本地机器指令)。通过这种方式,原来任何通过绝对路径引用了该odex文件的代码就都不需要修改了。
三.oat文件格式#
借助罗大神的图我们可以知道,OAT文件本质上是一个ELF文件,因此在最外层它具有一般ELF文件的结构,例如它有标准的ELF文件头以及通过段(Section)来描述文件内容。
OAT文件包含有两个特殊的段oatdata和oatexec,前者包含有用来生成本地机器指令的dex文件内容,后者包含有生成的本地机器指令,它们之间的关系通过储存在oatdata段前面的oat头部描述。
APK安装过程中生成的OAT文件的输入只有一个DEX文件,也就是来自于打包在要安装的APK文件里面的classes.dex文件。实际上,一个OAT文件是可以由若干个DEX生成的。这意味着在生成的OAT文件的oatdata段中,包含有多个DEX文件。详细分析请移步Android运行时ART加载OAT文件的过程分析
四.multidex加载odex,multidex和oat的关系
MultiDex在dalvik虚拟机上的简要安装过程:
将/data/app/apkName.apk路径下解压得到的classes2.dex, …, classesN.dex,依次写入到/data/data/pkgName/code_cache/secondary-dexes/apkName.apk.classes2.zip等zip文件的classes.dex中,并返回这个zip列表。然后针对这个zip列表执行安装过程,具体过程是,将这个要安装的zip列表加入BaseDexClassLoader的pathList实例的dexElements数组中,其中会针对各dex文件进行dex2opt优化。一旦加入到了dexElements数组中,程序启动的时候,ClassLoader会加载dexElements数组中的元素,从而实现multi dex的安装。
上面提到OAT文件可以由若干个dex生成,也就是不需要multidex去进行安装,但是multidex是application中
进行Install的,跟虚拟机关系不大。
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
在install函数中在执行从提取dex文件列表前会做一些校验操作,其中包含检查APK是否已安装,若APK已安装,则不进行后续操作。检查SDK版本号,版本号大于20不能保证MultiDex可正常Work
Set var2 = installedApk;
synchronized(installedApk) {
String apkPath = e.sourceDir;
if(installedApk.contains(apkPath)) {
return;
}
所以multidex在ART上不会影响程序的逻辑,它和ART没有关系~。。。。
multidex源码分析:MultiDex安装过程源码分析
小结:
从安装过程上来看
Java的代码实际上需要两次“转换”才可以在android设备上运行
一.PC端:.class->.dex->.apk
二.phone:dex->odex
区别在于第二步。
ART : .dex->.odex(机器码)(AOT Ahead-Of-Time)
Dalvik: .dex->.odex(字节码)(JIT Just-In-Time)
机器码可直接执行,而字节码每次启动都需要执行将优化过的odex字节码再转换成机器码
ART优缺####
系统性能大幅提升
App启动、运行更快
减少每次启动的编译增加电池续航
存储占用更大
安装时间更长
复制粘贴+理解,,,希望以后忘了能回来看看~!~
关注微信公众号 Android历练记 或扫一扫二维码:
让我们一起来搞事情。