Dex文件加载以及类加载流程

Dex文件加载以及类加载流程
安卓源码连接:http://androidxref.com/4.4.4_r1
app在启动的过程中创建了PathClassLoader加载dex文件,那么我们跟进PathClassLoader:
/libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java:
在这里插入图片描述
构造函数直接调用了父类的方法,我们查看BaseDexClassLoader的方法:构造函数里返回了一个DexPathList的实例
在这里插入图片描述
跟进DexPathList:
在这里插入图片描述
在这里插入图片描述
构造函数里面有个重要的 makeDexElements方法返回了一个Element数组,而Element类主要是用来保存dex或资源文件路径的类:
在这里插入图片描述
makeDexElements遍历所有资源文件,并调用loadDexFile来加载dex文件,它最终返回一个DexFile结构对象。接着分析loadDexFile函数:
在这里插入图片描述
这里出现了两种情况,1是没有设置保存优化dex目录的时候,则直接创建一个DexFile对象,2是直接调用DexFile类的loadDex方法完成家在解析dex工作:
第一种情况:
在这里插入图片描述
第二种情况:
在这里插入图片描述
都调用了openDexFile函数返回了mcookie这个int值:openDexFile值最终调用了openDexFileNative这个方法
在这里插入图片描述
去native源码查看这个函数的定义:
在这里插入图片描述
重要的有两个函数,1是dvmRawDexFikeOpen,2是dvmJarFileOpen这两个,顾名思义,1是加载Dex,2是加载Jar。
跟进dvmRawDexFikeOpen:
在这里插入图片描述
首先跟进dex文件的优化,dvmOptimizeDexFile:
在这里插入图片描述
新开了一个子进程调用opt进行优化,那么我们去看一下opt程序是怎样进行优化的-/dalvik/dexopt/OptMain.cpp:
在这里插入图片描述
调用FromDex方法进行优化,Fromdex方法里主要调用了两个方法:
在这里插入图片描述
这里我们关注dvmContinueOptimization这个进行实际优化工作的函数:
先放一张图
在这里插入图片描述
代码层面:
在这里插入图片描述
看到了熟悉的早期加固的脱壳关键函数dvmDexFileOpenPartial函数:第一个参数dex地址、第二个参数dex大小,跟进这个函数,最终会调用DexFileParse来解析Dex文件,这也是一个脱壳点:
在这里插入图片描述
这里就看完了优化的过程,紧接着回到dvmRawDexFikeOpen,看完了优化来看解析:
在这里插入图片描述
在这里插入图片描述
跟进FileParse函数:
在这里插入图片描述

FileParse函数执行完成后,Dex文件的解析也告一段落,接下来就该分析类加载了,类加载机制接下来的工作就是根据虚拟机的运行需要,从Dex文件中加载指定类,并将其装入虚拟机的运行时环境中。类加载的目的其实就是为所需的类生成一个ClassObject的实例,然后需要的时候调用这个实例对象。
回到最开始的BaseClassLoader:获得DexPathList的实例化对象后,调用DexPathList类的findclass方法,由findclass方法(往里面深入findclass方法最终调用了findClassNoInit方法)来在dalvik中得到该类的ClasssObject。
在这里插入图片描述
在这里插入图片描述
之前element数组的操作如下:可见里面存放了dex文件和其他资源文件。
在这里插入图片描述
findclass又调用了DexFile的loadclassBinaryName方法:
在这里插入图片描述
loadclassBinaryName又调用了defineClass方法:
在这里插入图片描述
defineClass又调用了defineClassNative方法:
在这里插入图片描述
defineClassNative方法里又调用了dvmDefineClass方法:
在这里插入图片描述
dvmDefineClass方法又调用了findClassNoInit方法:
在这里插入图片描述
findClassNoInit方法首先调用dvmLookupClass判断本类是否已经被加载,若已加载,直接使用,结束函数。

dvmLookupClass函数如下,作用是调用dvmHashTableLookup在哈希表中判断本类是否已经被加载,若找到返回类在dex文件地址,否则返回null:
在这里插入图片描述
回到findClassNoInit方法中,如果没有找到:
在这里插入图片描述
若是用户类,则调用dexfindclass得到DexClassDef类的实例化对象,然后利用这个对象调用loadClassFromDex得到该类的ClassObject结构体。之后将加载了的这个类的ClassObject对象添加到全局变量gDvm的loadedClasses成员中,该成员主要是保存加载到内存中的类对象。当Dalvik要运行某一个类方法的时候,是通过运行在内存中的ClassObject对象中的资源去执行,最后调用dvmInterpret方法初始化解释器并执行字节码指令。
在这里插入图片描述
下面我们来看下在dalvik在加载过程中使用到的数据结构:
 Method: java方法在dalvik中的结构体,是dalvik的执行单位;拥有指向字节码指令的指针insns,是ClassObject结构体中的成员之一
 ClassObject: java类在dalvik中的结构体,包含多个Method结构;拥有指向DvmDex的指针;拥有指向加载该类的ClassLoader指针
 DvmDex: 拥有指向dexFile的指针
 dexFile: dex在dalvik的描述结构

猜你喜欢

转载自blog.csdn.net/weixin_42011443/article/details/106129466