Android中dex文件的加载与优化流程

Android中dex文件的加载与优化流程目录1、dex文件分析…12、odex文件…22.1、odex文件结构…22.2、odex文件结构分析…33、dex文件的验证与优化…33.1dex文件加载流程…33.2dex文件优化加载流程图…4 1、dex文件分析逻辑上,可以把dex文件分成3个区,头文件、索引区和数据区。索引区的ids后缀为i

大家好,又见面了,我是你们的朋友全栈君。

目录

1、dex文件分析1

2、odex文件2

2.1、odex文件结构2

2.2、odex文件结构分析3

3、dex文件的验证与优化3

3.1 dex文件加载流程3

3.2 dex文件优化加载流程图4

 

1、dex文件分析

逻辑上,可以把dex文件分成3个区,头文件、索引区和数据区。索引区的ids后缀为identifiers的缩写。

Android中dex文件的加载与优化流程

header

dex文件里的header。除了描述.dex文件的文件信息外,还有文件里其他各个区域的索引。

Android中dex文件的加载与优化流程

(1)           magic value,这8个字节一般是常量,为了使.dex文件能够被识别出来,它必须出现在.dex文件的最开头的位置。

(2)           checksum和signature.文件校验码,使用alder32算法校验文件出去maigc,checksum外余下的所有文件区域,用于校验文件错误。Signature,使用SHA-1算法hash除去magic,checksum和signature外余下的所有文件区域。

(3)           file_size:Dex文件的大小。

其余的属性,因为在加固中没有用到。这里就不对它们进行过多解释。

2、odex文件

odex是OptimizedDEX的缩写,表示经过优化的dex文件。存放在/data/dalvik-cache目录下。由于Android程序的apk文件为zip压缩包格式,Dalvik虚拟机每次加载它们时需要从apk中读取classes.dex文件,这样会耗费很多cpu时间,而采用odex方式优化的dex文件,已经包含了加载dex必须的依赖库文件列表,Dalvik虚拟机只需检测并加载所需的依赖库即可执行相应的dex文件,这大大缩短了读取dex文件所需的时间。

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

2.1、odex文件结构

Odex文件的结构可以理解为dex文件的一个超集。它的结构如下图所示,odex文件在dex文件头部添加了一些数据,然后在dex文件尾部添加了dex文件的依赖库以及一些辅助数据。

 
 

Android中dex文件的加载与优化流程

 

 

 

Dalvik虚拟机将dex文件映射到内存中后是Dalvik格式,在Android系统源码的dalvik/libdex/DexFile.h文件中它的定义如下。

DexFile结构中存入的多为其他结构的指针。DexFile最前面的DexOptHeader就是odex的头,DexLink以下的部分被成为auxillary section,即辅助数据段,它记录了dex文件被优化后添加的一些信息。然而,DexFile结构描述的是加载进内存的数据结构,还有一些数据是不会加载进内存的,经过分析,odex文件结构定义整理如下.

Android中dex文件的加载与优化流程

Struct ODEXFile{

           DexOptHeader             header;    /*odex文件头*/

           DEXFile                          dexfile;  /*dex文件*/

           Dependences              deps;        /*依赖库列表*/

           ChunkDexClassLookup    lookup;     /*类查询结构*/

           ChunkRegisterMapPool          mappool; /*映射池*/

           ChunkEnd                            end;    /*结束标志*/

};

2.2、odex文件结构分析

         ODEXFile的文件头DexOptHeader在DexFile.h文件中定义如下.

struct DexOptHeader{

         u1  magic[8];                  /*odex版本标识 */

         u4  dexOffset;            /* dex文件头偏移*/

         u4  dexLength;      /* dex文件总长度*/

         u4  depsOffset;      /*odex依赖库列表偏移*/

         u4  depsLength;     /*依赖库列表总长度*/

         u4  optOffset;       /*辅助数据偏移*/

         u4  optLength;       /*辅助数据总长度*/

         u4  flags ;                          /*标志*/

         u4  checksum;        /*依赖库与辅助数据的校验和*/

};

3、dex文件的验证与优化

3.1 dex文件加载流程 

Android提供了一个专门验证与优化dex文件的工具dexopt。其源码位于Android系统源码的dalvik/dexopt目录下,Dalvik虚拟机在加载一个dex文件时,通过指定的验证与优化选项来调用dexopt进行相应的验证与优化操作。

         dexopt的主程序为OptMain.cpp,其中处理apk/jar/zip文件中的classes.dex的函数为extractAndProcessZip(),extractAndProcessZip()首先通过dexZipFindEntry()函数检查目标文件中是否拥有class.dex,如果没有就失败返回,成功的话就调用dexZipGetEntryInfo()函数来读取classes.dex的时间戳与crc校验值,如果这一步没有问题,接着调用dexZipExtractEntryTo-File()函数释放classes.dex为缓存文件,然后开始解析传递过来的验证与优化选项,验证选项使用“v=”指出,优化选项使用“o=”指出。所有的预备工作都做完后,调用dvmPrepForDexOpt()函数启动一个虚拟机进程,在这个函数中,优化选项dexOptMode与验证选项varifyMode被传递到了全局DvmGlobals结构gDvm的dexOptMode与classVerifyMode字段中。这时候所有的初始化工作已经完成,dexopt调用dvmContinueOptimization()函数开始真正的验证和优化工作。

         dvmContinueOptimization()函数的调用链比较长。首先从OptMain.cpp转移到、dalvik/vm/analysis/DexPrepare.cpp,因为这里有dvmContinueOptimization()函数的实现。函数首先对dex文件做简单的检查,确保传递进来的目标文件属于dex或odex,接着调用mmap()函数将整个文件映射到内存中,然后根据gDvm的dexOptMode与classVerifyMode字段来设置doVarify与doOpt两个布尔值,接着调用rewriteDex()函数来重写dex文件,这里的重写内容包括字符调整、结构重新对齐、类验证信息以及辅助数据。rewriteDex()函数调用dexSwapAndVerify()调整字节序,接着调用dvmDexFileOpenPartial()创建DexFile结构,dvmDexFileOpenPartial()函数的实现在Android系统源码dalvik/vm/DvmDex.cpp文件中,该函数调用dexFileParse()函数解析dex文件,dexFileParse()函数读取dex文件的头部,并根据需要调用验证dexComputeChecksum()函数或调用dexComputeOptChecksum()函数来验证dex或odex文件爱你头的checksum与signature字段。

         接着回到DvmDex.cpp文件继续看代码,当验证成功后,dvmDexFileOpenPartial()函数调用allocateAuxStructures()函数设置DexFile结构辅助数据的相关字段,最后执行完后返回到rewriteDex()函数。rewriteDex()接下来调用loadAllClasses()加载dex文件中所有的类,如果这一步失败了,程序等不到后面的优化与验证就退出了,如果没有错误发生,会调用verifyAndOptimizeClasses()函数进行真正的验证工作,这个函数会调用verifyAndOptimizeClass()函数来优化与验证具体的类,而verifyAndOptimizeClass()函数会细分这些工作,调用dvmVerifyClass()函数进行验证,再调用dvmOptimizeClass()函数进行优化。

         dvmVerifyClass()函数的实现代码位于Android系统源码的dalvik/vm/analysis/DexVerify.cpp文件中。这个函数调用verifyMethod()函数对类的所有直接方法与虚方法进行验证,verifyMethod()函数具体的工作是先调用verifyInstructions()函数来验证方法中的指令及其数据的正确性,再调用dvmVerifyCodeFlow()函数来验证代码流的正确性。

         dvmOptimizeClass()函数的实现代码位于Android系统源码的dalvik/vm/analysis/Optimize.cpp文件爱你中。这个函数调用optimizeMethod()函数对类的所有直接方法与虚方法进行优化,优化的主要工作是进行“指令替换”,替换原则的优先级为“volatile”替换-正确性替换-高性能替换。比如指令iget-wide会根据优先级替换为“volatile”形式的iget-wide-volatile,而不是高性能的iget-wide-quick.

         rewriteDex函数返回后,会再次调用dvmDexFileOpenPartial()来验证odex文件,接着调用dvmGenerateRegisterMaps()函数来填充辅助数据区结构,填充结构完成后,接下来调用updateChecksum()函数重写dex文件爱你的checksum值,再往下就是writeDependencies()与writeOptData()了。

3.2 dex文件优化加载流程图

 Android中dex文件的加载与优化流程

Android中dex文件的加载与优化流程

Android中dex文件的加载与优化流程

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/153553.html原文链接:https://javaforall.net

(0)
上一篇 2022年6月27日 上午10:46
下一篇 2022年6月27日 上午10:46


相关推荐

  • Idea激活码最新教程2023.1.1版本,永久有效激活码,亲测可用,记得收藏

    Idea激活码最新教程2023.1.1版本,永久有效激活码,亲测可用,记得收藏Idea 激活码教程永久有效 2023 1 1 激活码教程 Windows 版永久激活 持续更新 Idea 激活码 2023 1 1 成功激活

    2025年5月26日
    4
  • jvm之指令重排_java指令重排

    jvm之指令重排_java指令重排引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序;在特定情况下,指令重排将会给我们的程序带来不确定的结果…..1. 什么是指令重排?     在计算机执行指令的顺序在经过程序编译器编译之后形成的指令序列,一般而言,这个指…

    2022年8月31日
    4
  • 怎么新建pytest的ini文件_python读取ini配置文件

    怎么新建pytest的ini文件_python读取ini配置文件前言pytest配置文件可以改变pytest的运行方式,它是一个固定的文件pytest.ini文件,读取配置信息,按指定的方式去运行查看pytest.ini的配置选项pytest-h找到以下

    2022年7月29日
    6
  • ubuntu安装python3.7,并更新python默认指向为python3.7

    ubuntu安装python3.7,并更新python默认指向为python3.7ubuntu默认带着的python版本不是最新版,因此需要手动安装最新版。查看python的指向。ls-l/usr/bin|greppython可以看到,此时python指向的是python3.4。第一部分:安装python3.71.直接使用apt-get安装python3.7失败:apt-getinstallpython3.72.改为手动安装…

    2022年6月23日
    60
  • 硬件接口之Camera DVP「建议收藏」

    硬件接口之Camera DVP「建议收藏」Camera的并口传输方式很多地方叫做dvp接口,但是并没有统一的标准。MIPI接口比DVP的接口信号线少,由于是低压差分信号,产生的干扰小,抗干扰能力也强。最重要的是DVP接口在信号完整性方面受限制,速率也受限制。500W还可以勉强用DVP,800W及以上都采用MIPI接口。1.DVP的信号脚名称及作用:PCLK:pixelclock,像素时钟,每个时钟对应一个像素数据;HSYNC:horizonalsynchronization,行同步信号VSYNC:verticalsynchro

    2022年5月2日
    72
  • Java多线程常用面试题(含答案,精心总结整理)

    Java多线程常用面试题(含答案,精心总结整理)Java并发编程问题是面试过程中很容易遇到的问题,提前准备是解决问题的最好办法,将试题总结起来,时常查看会有奇效。现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉。这个多线程问题比较简单,可以用join方法实现。核心:thread.Jo

    2022年7月15日
    24

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号