Android的APK安装过程 JVM Dalvik和ART等虚拟机区别以及DEX文件ODEX文件OAT文件区别

APK

  • APK
  • JVM Dalvik ART区别
    • ART的运行原理:
  • DEX文件
  • ODEX文件
  • OAT文件
  • APK安装过程

APK

apk全称是AndroidPackage,也就是Android安装包;APK的本质是一个zip压缩包,如果将后缀名改成.zip,就可以解压,APK 文件与 Zip 文件最大的一个不同是 APK 包含签名信息,用于保证安装包安全不被修改,解压后的目录有:

  • res文件夹:用于存放Android资源文件的目录,里面有drawable图片资源,布局文件等,这里面的文件都是被编译过的(图片除外)
  • assets目录:用于存放需要打包到APK中的静态文件,文件没有进行编译
  • META-INF目录:即Metadata infomation元数据(又称中介数据、中继数据,用于描述数据的数据)信息目录,里面有MANIFEST.MF:摘要文件,列出了apk的所有文件,以及这些文件内容所对应的base64-encoded SHA1 哈希值,用于验证apk文件的完整性,判断apk是否被篡改;CERT.SF:摘要签名文件,它列出了MANIFEST.MF这个文件中每条信息的hash值,用于验证摘要文件是否被篡改;CERT.RSA:该文件保存了解密用的公钥,以及加密算法等信息等
  • AndroidManifest.xml:Android的应用配置文件,描述了应用的总体信息,需要使用的用户权限以及组件等等,已被编译
  • resources.arsc:资源配置文件,用于记录资源文件与资源id之间的映射关系,res/values中的信息大部分被编译在此处
  • lib目录:Android依赖的Native库的目录,其中会根据不同的cpu架构分为多个子目录
  • classes.dex:能用于dalvik执行的字节码,由多个.class的Java字节码文件组合而成

JVM Dalvik ART区别

虽然说Android是基于Java的,Java使用JVM,但是Google为了更好的适应手机的特性(其实就是当时手机的硬件资源很有限,直接使用JVM,效果差),在JVM的基础上优化出了Dalvik/ART虚拟机(由此引发了多年的官司,不过最终跟Oracle打赢官司的希望还是很渺茫的)

  • JVM加载的是.class文件,Dalvik虚拟机加载的是.dex文件

  • JVM基于栈,DVM基于寄存器:
    JAVA虚拟机基于栈结构,程序在运行时虚拟机需要频繁的从栈上读写数据,这个过程需要很多其它的指令分派与内存訪问次数,会耗费非常多CPU时间。
    Dalvik虚拟机基于寄存器架构。数据的訪问通过寄存器间直接传递,这种訪问方式比基于栈方式要快非常多

    以下面这段代码为例:

    public class Hello {
        public int calc(int a, int b) {
            return (a + b) * (a - b);
        }
    
        public static void main(String[] args) {
            Hello h = new Hello();
            System.out.print(h.calc(5, 3));
        }
    }
    

    将其编译成class文件后,通过javap -c Hello.class > hello.txt 反编译后打开hello.txt文件查看相关字节码

    public int calc(int, int);
    Code:
         0: iload_1 //将第二个int型本地变量推送至栈顶
         1: iload_2 // 将第三个int型本地变量推送至栈顶
         2: iadd // 将栈顶两int型数值相加并将结果推送至栈顶
         3: iload_1 // 将第二个int型本地变量推送至栈顶
         4: iload_2 // 将第三个int型本地变量推送至栈顶
         5: isub // 将栈顶两int型数值相减并将结果推送至栈顶
         6: imul // 将栈顶两int型数值相乘并将结果推送至栈顶
         7: ireturn // 从当前方法返回int值
    

    相同代码,编译成dex文件,再反编译,查看字节码

             0000: add-int  v0, v3, v4
             0002: sub-int  v1, v3, v4
             0004: mul-int/2addr  v0, v1
             0005: return  v0
    

    可以看到代码指令只有一半,运行的效率自然就要高很多了,执行流程如图
    Android的APK安装过程 JVM Dalvik和ART等虚拟机区别以及DEX文件ODEX文件OAT文件区别_第1张图片

  • 再来看看Android4.4新增加的ART,想了解它,首先了解JIT(Just In Time。即时编译技术)和AOT(Ahead Of Time,预编译技术)两种编译技术:
    JIT以JVM为例,javac把程序源代码编译成class字节码,JVM通过逐条解释字节码将其翻译成相应的机器指令,逐条读入,逐条解释翻译,运行速度必定比C/C++编译后的可运行二进制字节码程序慢,为了提高运行速度,就引入了JIT技术。JIT会在运行时分析应用程序的代码,识别哪些方法能够归类为热方法,这些方法会被JIT编译器编译成相应的汇编代码,然后存储到代码缓存中。以后调用这些方法时就不用解释运行了,能够直接使用代码缓存中已编译好的汇编代码,这能显著提升应用程序的运行效率(安卓Dalvik虚拟机在2.2中添加了JIT)

    相对的AOT就是指C/C++这类语言,编译器在编译时直接将程序源代码编译成目标机器码,运行时直接运行机器码。

    Dalvik虚拟机运行的是dex字节码,而ART虚拟机运行的是本地机器码

    Dalvik运行的是dex字节码,依靠JIT编译器去解释运行;运行时动态地将运行频率非常高的dex字节码翻译成本地机器码,然后再运行,可是将dex字节码翻译成本地机器码是发生在应用程序的运行过程中,而且应用程序每一次运行的时候,都要做一次这个翻译工作,因此即使使用了JIT,Dalvik虚拟机的整体性能还是不能与直接运行本地机器码的ART虚拟机相比

    在ART下,Android 应用在安装后,会进行一次预编译,将应用安装包中的dex字节码转换成机器码存储在本地(系统只能运行二进制程序),这样,应用在运行时,可以直接执行这些二进制程序,移除了运行时的解释运行,效率更高,启动更快,不过这样做导致了安装后应用所占的空间更大,安装时间更长

ART的运行原理:

  • 在Android系统启动过程中创建的Zygote进程利用ART运行时导出的Java虚拟机接口创建ART虚拟机。

  • APK在安装的时候,打包在里面的classes.dex文件会被工具dex2oat翻译成本地机器指令,最终得到一个ELF格式的oat文件。

  • APK运行时,上述生成的oat文件会被加载到内存中,并且ART虚拟机可以通过里面的

    1.oatdata和oatexec段找到任意一个类的方法对应的本地机器指令来执行。
    2.oat文件中的oatdata包含用来生成本地机器指令的dex文件内容
    3.oat文件中的oatexec包含有生成的本地机器指令。

ART优点:

  1. 系统性能的显著提升
  2. 应用启动更快、运行更快、体验更流畅、触感反馈更及时
  3. 更长的电池续航能力

ART缺点:

  1. 更大的存储空间占用,可能会增加10%-20%
  2. 更长的应用安装时间

DEX文件

对于android应用程序,本质上使用的是java开发,使用标准的java编译器编译出Class文件,和普通的java开发不同的地方是把class文件再重新打包成dex类型的文件,这种重新打包会对Class文件内部的各种函数表、变量表等进行优化,最终产生了dex文件

ODEX文件

odex文件是dalvik虚拟机对解压出来的class.dex文件做一定程度的优化,文件大小会减少,存放在/data/dalvik-cache目录下,这样做可以加快软件的启动速度,预先提取,减少对RAM的占用

不过,这个优化过程会根据不同设备上Dalvik虚拟机的版本、Framework库的不同等因素而不同。在一台设备上被优化过的ODEX文件,拷贝到另一台设备上不一定能够运行。

ODEX 文件比 DEX 文件更难反编译,这也在一定程度上提高了安全性,因此在一些系统预装或系统级应用大多采用了 ODEX 优化。

一般 ODEX 不直接运行,在 Dalvik 运行 ODEX 时,需要通过Just-In-Time(JIT)编译器进行优化,提高运行效率。JIT 是一种在运行时同步将字节码转化成机器码的编译器,Dalvik 直接运行转化后的机器码

ODEX的内容有odex文件头-dex文件-依赖库-辅助数据,odex文件在原来的dex文件头添加了一些数据,在文件尾部添加了程序运行时需要的依赖库和辅助数据,使得程序运行速度加快。

OAT文件

OAT 文件是 ART 运行的文件,是一种二进制可运行文件,包含 DEX 文件和编译出的本地机器指令文件,其文件格式类似于网络数据报文,包含文件头和文件体,文件头的 oatdata、oatexec 和 oatlastword 字段分别描述 DEX 文件位置和本地机器指令的起止位置。因为 OAT 文件包含 DEX 文件,因此比 ODEX 文件占用空间更大

由于其在安装时打包在里面的classes.dex文件会被工具dex2oat翻译成本地机器指令,最终得到一个ELF格式的OAT文件,ART 加载 OAT 文件后不需要经过处理就可以直接运行,它没有了从字节码装换成机器码的过程,因此运行速度更快。

APK安装过程

一个APK放到手机上执行安装会涉及到如下几个目录

  • /data/app:存放用户安装的apk,安装时会把apk复制到这里
  • /data/data:应用安装完成后,会在该目录下生成与apk包名一样的文件夹,用于存放应用数据
  • /data/dalvik-cache:存放apk的odex文件,便于应用启动时直接执行

首先,系统会把apk复制到/data/app下,然后通过META-INF下的文件校验apk的签名是否正确,检查apk的结构是否正常,进而解压并校验dex文件。如果dex文件没有被破坏,则会把dex文件优化为odex文件,使得程序的启动时间加快,同时,在/data/data目录下建立与apk包名相同的文件夹。如果apk中有Native库,lib目录的话,系统会判断so库的名字是否正确,并根据系统cpu架构解压对应的so库到/data/data/packagename/lib下。

你可能感兴趣的:(【Android常用开发】)