新书上市《深入解析Android 5.0系统》

以下内容节选自本书


Android4.4最大的变化就是引入ART模式来代替Dalvik虚拟机。ART是AndroidRuntime的缩写,它提供了以AOT(Ahead-Of-Time)的方式运行Android应用程序的机制。所谓AOT是指在运行前就把中间代码静态编译成本地代码,这就节省了JIT运行时的转换时间。因此,和采用JIT的Dalvik相比,ART模式在总体性能有了很大的提升,应用程序不但运行效率更高,耗电量更低,而且占用的内存也更少
ART和dalvik相比,系统的性能得到了显著提升,同时占用的内存更少,因此能支持配置更低的设备。但是ART模式下编译出来的文件会比以前增大10%-20%,系统需要更多的存储空间,同时因为在安装时要执行编译,应用的安装时间也比以前更长了。


ART和dalvik相比,系统的性能得到了显著提升,同时占用的内存更少,因此能支持配置更低的设备。但是ART模式下编译出来的文件会比以前增大10%-20%,系统需要更多的存储空间,同时因为在安装时要执行编译,应用的安装时间也比以前更长了。

开启ART模式


在Android中ART模式缺省是关闭的,如果我们希望启动ART模式,需要在“设置”应用中手工打开它。进入“设置”后,选择“开发者选项”,再点击“选择运行环境”,会弹出如选择DALVIK或ART的对话框。选择ART后,系统将会重新启动,然后系统的运行环境就会从Dalvik切换到ART模式。
让我们打开“设置”应用的代码,看看这种切换到底做了些什么。下面是DevelopmentSettings.java中的一段代码:
builder.setPositiveButton(android.R.string.ok, newOnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SystemProperties.set(SELECT_RUNTIME_PROPERTY,newRuntimeValue);
pokeSystemProperties();
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
pm.reboot(null);
}
});
上面这段代码只是设置重新设置了属性SELECT_RUNTIME_PROPERTY的值,然后就重启设备。这个属性的定义如下:
String SELECT_RUNTIME_PROPERTY = "persist.sys.dalvik.vm.lib"
注意属性是以persist开头的,所以它的值在重新开机后也可以保存。这个属性定义的是当前使用的运行环境库,如果是dalvik,它的值为libdvm.so,如果是art,它的值为libart.so。通过这个属性,系统就能判断出需要运行的模式。
ART系统的源码位于目录art下,包含了以下目录:
build目录:存放了一些mk文件。
compiler目录:动态库libart-compiler.so的源码目录,它包含了一个ART的编译器。
dalvikvm目录:可执行文件dalvikvm的源码目录。
dex2oat目录:可执行文件dex2oat的源码目录。用来将dex格式的文件编译成可执行文件。dex2oat文件会链接libart-compiler动态库。
jdwpspy目录:可执行文件jdwpspy的源码目录。这是一个调试工具,通过socket接收VM中输出的消息并打印输出。
oatdump目录:可执行文件oatdump的源码目录。这是一个工具,能dump出art文件的信息。
runtime目录:动态库libart.so的源码目录。
test目录:包含了大量测试代码的目录。
tools目录:包含了几个脚本文件。

两种模式的区别


从系统的实现角度看,ART和Dalvik的区别只表现在两个地方。一处是在安装应用执行优化时,Dalvik模式下执行的是dexopt程序,而ART模式下执行的是dex2oat程序。这个在“11.5.5节dexopt(优化)命令”中已经介绍过来。通过dex2oat程序编译后得到的是elf格式的可执行文件,而不是以前的dalvik字节码了。
另一处是在运行应用时,Dalvik模式下系统为应用进程链接的是libdvm.so,而ART模式下链接的是libart.so。这两个库文件能够相互替换,是因为它们都实现了相同的接口。下面我们看看Android是如何来装载不同运行库的。
前面我们已经介绍过了,Zygote进程启动时会调用AndroidRuntime的start()函数来启动虚拟机,start()函数中有下面两行代码:
void AndroidRuntime::start(const char* className, const char*options)
{
......
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
......
}
我们看看jni_invocation的Init()函数的代码:
bool JniInvocation::Init(const char* library) {
#ifdef HAVE_ANDROID_OS
char default_library[PROPERTY_VALUE_MAX]; //从property中得到运行库的名称
property_get(kLibrarySystemProperty,default_library, kLibraryFallback);
#else
const char* default_library =kLibraryFallback;
#endif
if (library == NULL) {
library =default_library;
}
handle_ = dlopen(library,RTLD_NOW);// 装载运行库
if (handle_ == NULL) {
...... //错误处理
}
// 装载三个VM的入口函数。
if(!FindSymbol(reinterpret_cast(&JNI_GetDefaultJavaVMInitArgs_),
"JNI_GetDefaultJavaVMInitArgs")) {
returnfalse;
}
if(!FindSymbol(reinterpret_cast(&JNI_CreateJavaVM_),
"JNI_CreateJavaVM")) {
returnfalse;
}
if(!FindSymbol(reinterpret_cast(&JNI_GetCreatedJavaVMs_),
"JNI_GetCreatedJavaVMs")) {
returnfalse;
}
return true;
}
JniInvocation的Init()函数中通过属性persist.sys.dalvik.vm.lib取得了运行库的名称,然后调用dlopen()来装载运行库,同时从动态库中读取了三个函数的地址,它们是JNI_GetDefaultJavaVMInitArgs(),JNI_CreateJavaVM()和JNI_GetCreatedJavaVMs()。这三个函数相当于是虚拟机的三个入口函数,通过调用它们,就能创建出虚拟机系统。

更多相关文章

  1. C语言函数的递归(上)
  2. [置顶] Android事件总线还能怎么玩?
  3. Mac下配置Android(安卓)Stuido的HTTP Proxy
  4. Android(安卓)通知使用权(NotificationListenerService)的使用
  5. Android(安卓)实例剖析之 notepad
  6. Android权限问题:Permission is only granted to system apps
  7. Android中把文件存放在SDCard
  8. 【Android】Android(安卓)Studio中新创建的app目录结构
  9. Android开机自动启动Wi-Fi热点的方法

随机推荐

  1. Android多屏幕适配
  2. Android 属性动画Property Animation(下)
  3. android log机制——输出log
  4. android霓虹灯源代码——基础编
  5. Android系统各种类型的service刨根解读
  6. Android 使用弹出对话框,报Unable to add
  7. Android重力感应 .
  8. Android WebView+JSON+JavaScript
  9. 【转】Android状态栏、导航栏、DecorView
  10. Mac下如何用USB调试Android真机