美文网首页
Android-类加载

Android-类加载

作者: 森屿暖茶 | 来源:发表于2021-02-07 09:24 被阅读0次

    双亲委托机制

    类在进行类加载的时候,把加载任务托管给父类加载器,如能加载成功,则返回,否则依次向子类加载器递归尝试类加载。

    意义:

    ①避免类的重复加载,父类加载已加载该类时,子ClassLoader就没有必要加载一次了。

    ②安全性,防止核心API被随意篡改。

    ClassLoader

    ClassLoader本身是一个抽象方法。它的主要实现类有BootClassLoader、PathClassLoader、DexClassLoader.

    BootClassLoader:用于加载Android Framwork层(SDK)的class文件

    PathClassLoader:用于Android应用程序加载器,可以加载指定的dex和jar、zip、apk中的classes.dex(系统使用)

    DexClassLoader:用于加载指定的dex和jar、zip、apk中的classes.dex。(供开发者使用)

    拓展:

    在API26之前。

    父类同是BaseDexClassLoader,唯一的区别是DexClassLoader使用自己传入的目录,PathClassLoader传空交给父类处理

    optimizedDirectory 参数就是dexopt的产出目录(odex)。那 PathClassLoader 创建时,这个目录为null,就

    意味着不进行dexopt?并不是, optimizedDirectory 为null时的默认路径为:/data/dalvik-cache。

    在API26之后DexClassLoader也取消了optimizedDirectory

    也就和PathClassLoader一样了

    热修复相关

    LoadClass:

    ClassLoader抽象类中实现。先找缓存,找不到在调用findClass

    findClass:PathClassLoader和DexClassLoader的父类BaseDexClassLoader中实现findClass。

    BaseDexClassLoader中

    名称为pathList的属性DexPathList(API 28) 从 pathList 中查找class(API 28) DexPathList的findClass方法,一个element对应一个dex,如果在前面的element加载到这个类就不管后面的element了  (API 28) Elements中的findClass方法 从dexFile中加载(native层加载) DexPathList 的makePathElements 用于加载dex文件转换为Element数组(API 28) DexPathList 中的Element数组 dexElements(API 28) makeDexElement(API 28) DexPathList 构造函数会调用makeDexElements方法生成dex的Element数组(API 28)

    PathClassLoader加载过后,pathlist 中存在一个Element数组,Element类中存在一个dexFile成员表示dex文件,即:APK中有X个dex,则Element数组就有X个元素。

    总结:

    可能看到这里我们比较乱了,理一下。一个类的加载经历了哪些。我们以PathClassLoader为例。

    ①加载一个类的时候,首先通过Class缓存寻找是否已经加载过该类。参考抽象类的loadClass方法。

    ②若在缓存中未找到该类,则交由父加载器加载该类。参考抽象类的loadClass方法。

    ③调用父加载器PathClassLoader的父类BaseDexClassLoader实现的findClass方法加载该类。

    ④PathClassLoader在初始化的时候调用父构造方法实例化DexPathList属性,DexPathList属性初始化时构造方法内通过makePathElements(或makeDexElements 不同API可能不同)加载APK内的dex文件生成Element数组。

    ⑤BaseDexClassLoader实现的findClass方法中顺序循环已存在的Element数组,通过Element中的DexFile加载类。。

    ⑥未找到,抛出类未找到异常。

    热修复(multide 形式(thinker、qfix))

    热修复的原理。我们只需在应用启动的时候,一般是在application方法中(因为class加载首先从缓存中加载),在应用启动后,经过PathClassLoader加载过后所有的类都在 pathList的Element 数组,把生成的Elment数组插入到PathList的Element数组的最前方。在加载类的时候就只会加载到我们需要更新的类了,因为是顺序寻找,找到就返回。(先从我们补丁的dex文件生成的element寻找,找不到再从APK的dex生成的element种寻找)。

    热修复基本思路总结:

    ①获取到当前引用的PathClassLoader

    ②反射获取其中DexPathList属性:DexPathList pathList.

    ③获取到补丁包path.dex文件的Element[]数组 pElements。参考PathClassLoader怎么把dex文件转换为Element数组的。于是我们反射执行DexPathList 中的makePathElements方法(视API而定)传入dex路径得到补丁包的element数组。

    ④获取pathList的dexElements数组。

    ⑤把补丁包的pElements数组合并到pathList的dexElements数组的前方,即newElements=pElements+dexElements

    ⑥反射赋值把newElements替换掉pathList的dexElements

    热修复没这么简单,还需考虑混淆,API版本不同导致的使用makePathElements方法或makeDexElements方法等因素。

    热修复(InstantRun 形式(Robust))待了解。

    相关文章

      网友评论

          本文标题:Android-类加载

          本文链接:https://www.haomeiwen.com/subject/ohmnoktx.html