美文网首页Android 热修复
Android热更新六:Qzone热更新原理

Android热更新六:Qzone热更新原理

作者: IT前沿技术分享 | 来源:发表于2019-03-29 09:08 被阅读88次

    很早之前就想深入的研究和学习一下热修复,由于时间的原因一直拖着,现在才执笔弄起来。


    Android而更新系列:
    Android热更新一:JAVA的类加载机制
    Android热更新二:理解Java反射
    Android热更新三:Android类加载机制
    Android热更新四:热修复机制
    Android热更新五:四大热修复方案分析
    Android热更新六:Qzone热更新原理
    Android热更新七:Tinker热更新原理
    Android热更新八:AndFix热更新原理
    Android热更新九:Robust热更新原理
    Android热更新十:自己写一个Android热修复


      超级补丁技术基于DEX分包方案,使用了多DEX加载的原理,大致的过程就是:把BUG方法修复以后,放到一个单独的DEX里,插入到dexElements数组的最前面,让虚拟机去加载修复完后的方法。


      当patch.dex中包含Test.class时就会优先加载,在后续的DEX中遇到Test.class的话就会直接返回而不去加载,这样就达到了修复的目的。

      但是有一个问题是,当两个调用关系的类不在同一个DEX时,就会产生异常报错。我们知道,在APK安装时,虚拟机需要将classes.dex优化成odex文件,然后才会执行。在这个过程中,会进行类的verify操作,如果调用关系的类都在同一个DEX中的话就会被打上CLASS_ISPREVERIFIED的标志,然后才会写入odex文件。

      所以,为了可以正常地进行打补丁修复,必须避免类被打上CLASS_ISPREVERIFIED标志,具体的做法就是单独放一个类在另外DEX中,让其他类调用。

      我们来逆向手机QQ空间APK看一下具体的实现:

      先进入程序入口QZoneRealApplication,在attachBaseContext中进行了两步操作:修复CLASS_ISPREVERIFIED标志导致的unexpected DEX problem异常、加载修复的DEX。

    1. 修复Unexpected DEX Problem异常

      先看代码,


      可以看到,这里是要加载一个libs目录下的dalvikhack.jar。在项目的assets/libs找到该文件,解压得到’classes.dex’文件,逆向打开该DEX文件,


      通过不同的DEX加载进来,然后在每一个类的构造方法中引用其他DEX中的唯一类AnitLazyLoad,避免类被打上CLASS_ISPREVERIFIED标志。


      在无修复的情况下,将DO_VERIFY_CLASSES设置为false,以提高性能。只有在需要修复的时候,才设置为true。


      至于如何加载进来,与下面第二个步骤基本相同。

    2. 加载修复的DEX

      从loadPatchDex()方法进入,经过几次跳转,到达核心的代码段,SystemClassLoaderInjector.c()。由于进行了混淆和多次方法的跳转,于是将核心代码段做了如下整理:

    修复的步骤为:

    1. 可以看出是通过获取到当前应用的Classloader,即为BaseDexClassloader
    2. 通过反射获取到他的DexPathList属性对象pathList
    3. 通过反射调用pathList的dexElements方法把patch.dex转化为Element[]
    4. 两个Element[]进行合并,把patch.dex放到最前面去
    5. 加载Element[],达到修复目的

    整体的流程图如下:


      从流程图来看,可以很明显的找到这种方式的特点:

    优势:

    没有合成整包(和微信Tinker比起来),产物比较小,比较灵活
    可以实现类替换,兼容性高。(某些三星手机不起作用)

    不足:
    1. 不支持即时生效,必须通过重启才能生效。
    2. 为了实现修复这个过程,必须在应用中加入两个dex!dalvikhack.dex中只有一个类,对性能影响不大,但是对于patch.dex来说,修复的类到了一定数量,就需要花不少的时间加载。对手淘这种航母级应用来说,启动耗时增加2s以上是不能够接受的事。
    3. 在ART模式下,如果类修改了结构,就会出现内存错乱的问题。为了解决这个问题,就必须把所有相关的调用类、父类子类等等全部加载到patch.dex中,导致补丁包异常的大,进一步增加应用启动加载的时候,耗时更加严重。

    相关文章

      网友评论

        本文标题:Android热更新六:Qzone热更新原理

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