-
Android 4.4提供了一种与Dalvik截然不同的运行环境ART(Android runtime)支持,ART源于google收购的Flexycore的公司。ART模式与Dalvik模式最大的不同在于,启用ART模式后,系统在安装应用的时候会进行一次预编译,将字节码转换为机器语言存储在本地,这样在运行程序时就不会每次都进行一次编译了,执行效率也大大提升。
虚拟机切换设置
Settings> Developer Options> Select Runtime
JniInvocation提供统一了接口:
libnativehelper\JniInvocation.cpp
1234567891011jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(
void
* vmargs) {
return
JNI_GetDefaultJavaVMInitArgs_(vmargs);
}
jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env,
void
* vm_args) {
return
JNI_CreateJavaVM_(p_vm, p_env, vm_args);
}
jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
return
JNI_GetCreatedJavaVMs_(vms, size, vm_count);
}
1234567891011extern
"C"
jint JNI_GetDefaultJavaVMInitArgs(
void
* vm_args) {
return
JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
}
extern
"C"
jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env,
void
* vm_args) {
return
JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
}
extern
"C"
jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
return
JniInvocation::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count);
}
12345static
JniInvocation* jni_invocation_;
void
* handle_;
//保存so库的首地址
jint (*JNI_GetDefaultJavaVMInitArgs_)(
void
*);
jint (*JNI_CreateJavaVM_)(JavaVM**, JNIEnv**,
void
*);
jint (*JNI_GetCreatedJavaVMs_)(JavaVM**, jsize, jsize*);
12345678910111213void
AndroidRuntime::start(
const
char
* className,
const
char
* options)
{
...
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if
(startVm(&mJavaVM, &env) !=
0
) {
return
;
}
onVmCreated(env);
...
}
123456789101112131415161718192021222324252627282930313233bool JniInvocation::Init(
const
char
* library) {
#ifdef HAVE_ANDROID_OS
char
default_library[PROPERTY_VALUE_MAX];
property_get(
"persist.sys.dalvik.vm.lib"
, default_library,
"libdvm.so"
);
#
else
const
char
* default_library =
"libdvm.so"
;
#endif
if
(library == NULL) {
library = default_library;
}
handle_ = dlopen(library, RTLD_NOW);
if
(handle_ == NULL) {
ALOGE(
"Failed to dlopen %s: %s"
, library, dlerror());
return
false
;
}
//查找JNI_GetDefaultJavaVMInitArgs函数指针
if
(!FindSymbol(reinterpret_cast<
void
**>(&JNI_GetDefaultJavaVMInitArgs_),
"JNI_GetDefaultJavaVMInitArgs"
)) {
return
false
;
}
//查找JNI_CreateJavaVM函数指针
if
(!FindSymbol(reinterpret_cast<
void
**>(&JNI_CreateJavaVM_),
"JNI_CreateJavaVM"
)) {
return
false
;
}
//查找JNI_GetCreatedJavaVMs函数指针
if
(!FindSymbol(reinterpret_cast<
void
**>(&JNI_GetCreatedJavaVMs_),
"JNI_GetCreatedJavaVMs"
)) {
return
false
;
}
return
true
;
}</
void
**></
void
**></
void
**>
12345678910bool JniInvocation::FindSymbol(
void
** pointer,
const
char
* symbol) {
*pointer = dlsym(handle_, symbol);
if
(*pointer == NULL) {
ALOGE(
"Failed to find symbol %s: %s\n"
, symbol, dlerror());
dlclose(handle_);
handle_ = NULL;
return
false
;
}
return
true
;
}
Dalvik字节码生成过程
应用安装时采用的代码优化方式不同:
Dalvik : dex2opt
ART : dex2oat
ART本地码生成过程
Dalvik dex代码经过dex => optimized dex => JIT cache这个过程,内存中需要同时容纳odex和JIT cache两份代码;换成ART以后,就变成dex => oat,内存里只放oat就可以。
两个运行环境产生的优化代码路径及文件名都为:/data/dalvik-cache/app/data@app@{package name}.apk@classes.dex,但是ART环境产生的优化代码文件大小明显比Dalvik环境产生大。OAT文件其实就是基于ELF格式的一种私有文件格式。
dex2oat编译过程
开发者开发出的应用程序经过编译和打包之后,仍然是一个包含dex字节码的APK文件。既然应用程序包含的仍然是dex字节码,而ART虚拟机需要的是本地机器码,这就必然要有一个翻译的过程。Android系统在应用程序安装时,通过dex2oat工具将应用的dex字节码翻译成本地机器码。
ART相关源代码:
OAT文件加载流程
1、读取oatdata符号地址获取Oat数据 startAddress。
2、读取oatlastword符号地址获取OAT数据 endAddress。
3、通过startAddress和endAddress定位Oat数据。
4、解析Oat数据。构建方法定位所需数据结构。
然后就可以调用加载OAT文件的代码了。
Android Dex vs ART 虚拟机运行效率提升
最新推荐文章于 2023-10-15 09:39:20 发布