Android预优化那些事

 https://blog.csdn.net/myfriend0/article/details/54970455

Android预优化那些事

Preopt ART Dalvik
APK的预优化原理和作用

1.什么是Android预优化

Android预优化,也就是把Android在启动或APP在运行时所需要做的一些事情,把这些事情转移到编译APK时完成,来达到更快的Android系统启动速度和更快的APP运行速度。

2.Android预优化的原理

先来回顾一下Android的发展史,在2014年的Google I/O大会上,Google隆重的发布了Android 4.4操作系统,其中有一个环节着重介绍了ART(Android runtime),也就是虚拟机,也就是运行APP的环境,也就是运行Java代码的虚拟机。虽然Android 4.4版本默认仍然用DVM(Dalvik VM),但到Android 5.0时ART就变成了默认模式,自此,DVM时代一去不再复返。
DVM和ART和Android的预优化有什么关系?先了解Java的几种虚拟机基本的工作机制:

  • (1)JVM:JVM虚拟机运行的是java字节码。Java文件到JVM的过程是:java -> java bytecode(class) -> java bytecode(jar)。
  • (2)DVM:DVM虚拟机解析执行的dex字节码。Java文件到DVM的过程是:java -> java bytecode(class) -> dalvik bytecode(dex)。
  • (3)ART:ART虚拟机执行本地机器码。Java文件到ART的过程是:java -> java bytecode(class) -> dalvik bytecode(dex) -> optimized android runtime machine code(oat)。

在Android 4.4(包括)之前用的是DVM,Android 4.4之后用的是ART,从java文件到虚拟机执行代码,ART比DVM多了oat的过程,ART所使用的AOT(Ahead-Of-Time)编译,在应用首次安装时,字节码预编译成机器码存在本地,而DVM是典型的JIT(Just-In-Time),在此模式下,应用每次运行的时候,字节码都需要即时编译器转换为机器码再执行,ART模式相对于DVM省去了解析字节码的过程,占用内存也相应减少,进而提高APP的运行效率,所以Andorid 5.0发布时,Google号称Android系统可以跑在512 M的内存的机器上,ART发挥了举足轻重的作用。

3.Android ART优化的过程

Zygote进程在启动的过程中,创建ART虚拟机。在ART中,打包在APK里面的Dex字节码是通过LLVM翻译成本地机器指令的。LLVM是一个用来快速开发自己的编译器的框架系统,在Dalvik运行时中,APK在安装的时候,安装服务PackageManagerService会通过守护进程installd调用一个工具 dexopt对打包在APK里面包含有Dex字节码的classes.dex进行优化,优化得到的文件保存在/data/dalvik-cache目录 中,并且以.odex为后缀名,表示这是一个优化过的Dex文件。在ART运行时中,APK在安装的时候,同样安装服务 PackageManager¬Service会通过守护进程installd调用另外一个工具dex2oat对打包在APK里面包含有Dex字节码进翻译。翻译后得到的是一个ELF格式的oat文件,这个oat文件同样是以.odex后缀结束,并且也是保存在/data/dalvik-cache目录中。

4.Android预优化的过程

在第三节可知,Android在首次启动和首次安装应用时,需要将字节码翻译成机器码,这样Android系统的启动速度将会大大减慢,如果没有预优化,APP的运行速度也会加上翻译所需要的时间。所以,这个翻译的工作需要转移到编译上面来,也就是所,在编译APK文件时,将会预先对APK进行翻译的优化,然后再打包到系统里面去,这样Android系统在首次启动时,就不再需要花费大量的时间去翻译APK的字节码。下文赘述这个过程的控制过程:
在项目的device.mk文件中有如下的配置:
这里写图片描述
如上图,当编译user版本时,WITH_DEXPREOPT将会置成true,
继续看WITH_DEXPREOPT的作用范围,如下:
这里写图片描述
在上图中,过滤各种条件,会执行LOCAL_DEX_PREOPT := $(DEX_PREOPT_DEFAULT)语句,而DEX_PREOPT_DEFAULT的定义在:
这里写图片描述
抛开其它条件,在user环境下编译,LOCAL_DEX_PREOPT会被置换成true,LOCAL_DEX_PREOPT是怎样控制编译呢?
这里写图片描述
在编译APP时,LOCAL_DEX_PREOPT是true,将会按照相应的规则优化APK文件,这个规则定在dex_preopt.mk文件中。

5.项目中执行的效果

在pixi5-5 4G的项目中Dialer、MMS、Contacts采用独立的仓库,服务器出版本的时候,不再编译源码中的这三个模块,而是已app list的方式,定制apk文件,所以就需要本地编译好apk文件,在上传到服务器。先来看看eng环境下(或关闭预优化)和user环境下编译App后会有什么不一样。
在eng环境下(或关闭预优化),以TctDialer为例,编译后输出的目录是这样的:
这里写图片描述
在看看user下编译的情况,编译后输出的目录是这样的:
这里写图片描述
对比可发现,没有预优化的apk文件有个classes.dex文件,而预优化的没有这个文件了,java代码跑哪里去了,可以看到输出目录多了oat子目录,编译后的java正好在这个目录下。
因此,在user环境下编译,生成的apk文件是不能直接上传到服务器的,因为这个apk已经没有java的代码了。所以在编译apk时,把mk文件中添加LOCAL_DEX_PREOPT := false把预编译关闭。

如果在user下编译的apk,push到daily的系统中,apk依然能够运行,不是没有classes.dex文件了吗?java代码都没有了,为什么还能运行?在第三节可知道,在android系统启动是会优化系统的app,所以daily中的APK的java代码被缓存到手机本地了,push user下编译的apk运行时依然运行的是daily版中apk缓存下来的code。

猜你喜欢

转载自blog.csdn.net/LoongEmbedded/article/details/81369694