热修复介绍

目录

1什么是热修复

2.为什么需要热修复

3.目前存在的解决方案

4.各自优缺点

5.如何应用和取舍


1.什么是热修复

传统发版流程。


传统发版流程

在这个流程当中发版重新上线需要用户重新下载覆盖安装无法做到全面替换,而且一次安装包较大用户安装的成本较高。

替代方案之一:Hybird.

缺点是采用H5以后性能与原生相比相差甚远。

更优的解决方案:热修复.

热修复的出现将传统发版流程修改成如下流程:


热修复流程

热修复流程在修复bug以后采用无感知方式直接推送给所有用户无需安装即可修复,有点是覆盖面广修复成功率高,且比下载一个apk安装成本要低。

2.为什么需要热修复

上面实际上已经解答了这个问题。

3.目前存在的解决方案:

阿里:andFix HotFix sophix

腾讯:Tinker  qq空间热补丁方案 

美团:Robust

根据不同技术方案实现重新对上述方案进行分类:

底层替换方案:AndFix

multidex方案:Tinker qq空间热补丁方案,nuwa等

基于instant run方案:robust.

3.1底层替换方案:

AndFix主要是在native层使用指针替换的方式替换bug方法,通过自定义注解找到需要修复的类和方法。首先类加载其方法都放在方法区,在native层中有相应的结构体描述对应的方法和执行逻辑,一旦某个方法出现bug,可以新建一个类然后把修复后的方法放进来,把原来的那个类的方法的指针指向新的类方法就完成了bug修复。


Sophix:是在AndFix进一步优化产生的,由于不同厂商的底层结构体不同,按照AndFix的方式很难兼容所有平台。而Sophix很巧妙的解决了这个问题,结构体的替换例如修改指针,改访问权限其前提是Android手机的结构体与AndFix的结构体要一致才能才能完好的进行替换,所以Sophix另辟蹊径采用整体替换的方式,

同包名访问权限问题采用classloader进行替换将新的替换为老的即可。


QQ超级补丁方案:

基于Android dex分包机制完成


dex分包

QQ超级补丁的原理基于Android dex加载原理,新修复的类放在patch.dex中插桩到dexElements最前面,就算是完成了bug热修复,虚拟机优先加载patch.dex中的qzone.class,为解决不在不同一个dex的两个调用类关系。也就是防止类被打上CLASS_ISPREVERIFIED标志,设计一个AntilazyLoad类,然后在所有类的构造方法中加入

if (ClassVerifier.PREVENT_VERIFY) { 

    System.out.println(AntilazyLoad.class);

 }

同时AntilazyLoad类会单独打包成hack.dex,这样所有的类都会引用不同的dex

qq超级补丁

修复的步骤为:

1.获取当前用的Classloader,即为BaseDexClassloader,目的会为了获取其pathlist

2.分别获取程序和补丁的pathList得到两者的dexElements然后进行合并,将补丁放到最前面

Tinker:

dalvik由于插桩导致耗时,性能损耗大,在art状态下修改方法和filed会导致内存指针异常,为了解决这个问题我们需要将修改了变量、方法以及接口的类的父类以及调用这个类的所有类都加入到补丁包中。这可能会带来补丁包大小的急剧增加。

全量替换新dex,对比新旧dex,在运行时将path.dex与旧dex还原成新的dex,DexDiff的细粒度是dex中每一项

缺点:

占用Rom体积;这边大约是你修改Dex数量的1.5倍(dexopt与dex压缩成jar)的大小。

一个额外的合成过程;虽然我们单独放在一个进程上处理,但是合成时间的长短与内存消耗也会影响最终的成功率。

难点:

Dex格式复杂;Dex大致分为像StringID,TypeID这些Index区域以及使用Offset的Data区域。它们有大量的互相引用,一个小小的改变可能导致大量的Index与Offset变化;

dex2opt与dex2oat校验;在这两个过程系统会做例如四字节对齐,部分元素排序等校验,例如StringID按照内容的Unicode排序,TypeID按照StringID排序...

低内存,快速;这要求我们对Dex每一块做到一次读写,无法像baksmali与dexmerge那样完全结构化。


robust


robust原理

遇到的难点:混淆以及super函数

缺点:太过复杂。无法做到资源.so库替换和AndFix类似也是方法替换


1.DexClassLoader和PathClassLoader.

DexClasLoader加载jar,dex以及apk的classes.dex文件,可以执行非安装程序代码

PathClassLoader是Android使用这个类作为系统和应用类的加载器。

#DexPathList

public Class findClass(String name) {

    for(Element element : dexElements) {

        DexFile dex = element.dexFile;

        if(dex !=null) {

           Class clazz = dex.loadClassBinaryName(name, definingContext);

            if(clazz !=null) {

                return clazz;

            }

        }

    }

    return null;

}

将dex转化成odex的过程中,会在DexVerify.cpp进行校验,验证如果直接引用到的类和clazz是否在同一个dex,如果是,则会打上CLASS_ISPREVERIFIED标志,需要阻止打上这个标记。


instant run原理


ART所使用的AOT(Ahead-Of-Time)编译,在应用首次安装时,字节码预编译成机器码存储在本地,也就是说在程序运行前编译。而Dalvik是典型的JIT(Just_In_Time),此模式下,应用每次运行的时候,字节码都需要即时编译器转换为机器码再执行,也就是在程序运行时编译。因此在App运行时,ART模式相对于Dalvik省去了解释字节码的过程,占用内存也相应减少,进而提高App。

   public int getIndex() {

    return 105;

}

public static ChangeQuickRedirect changeQuickRedirect;

public long getIndex() {

if(changeQuickRedirect != null) {

//PatchProxy中封装了获取当前className和methodName的逻辑,并在其内部最终调用了changeQuickRedirect的对应函数

if(PatchProxy.isSupport(new Object[0], this, changeQuickRedirect, false)) {

return ((Long)PatchProxy.accessDispatch(new Object[0], this, changeQuickRedirect, false)).longValue();

}

}

return 100L;

}

public class PatchesInfoImpl implements PatchesInfo { public ListgetPatchedClassesInfo() { ListpatchedClassesInfos = new ArrayList();

PatchedClassInfo patchedClass = new PatchedClassInfo("com.meituan.sample.d", StatePatch.class.getCanonicalName());

patchedClassesInfos.add(patchedClass);

return patchedClassesInfos;

}

}


public class StatePatch implements ChangeQuickRedirect {

@Override

public Object accessDispatch(String methodSignature, Object[] paramArrayOfObject) {

String[] signature = methodSignature.split(":");

if (TextUtils.equals(signature[1], "a")) {//long getIndex() -> a

return 106;

}

return null;

}

@Override

public boolean isSupport(String methodSignature, Object[] paramArrayOfObject) {

String[] signature = methodSignature.split(":");

if (TextUtils.equals(signature[1], "a")) {//long getIndex() -> a

return true;

}

return false;

}

}


直接用DexClassLoader加载修复包,然后用loadClass方法加载修复类,new出新对象,在用反射把这新的修复对象设置到指定类的changeQuickRedirect静态变量中即可。


第一次编译apk:

1.把Instant-Run.jar和instant-Run-bootstrap.jar打包到主dex中

2.替换AndroidManifest.xml中的application配置

3.使用asm工具,在每个类中添加$change,在每个方法前加逻辑

4.把源代码编译成dex,然后存放到压缩包instant-run.zip中

app运行期:

1.获取更改后资源resource.ap_的路径

2.设置ClassLoader。setupClassLoader:

使用IncrementalClassLoader加载apk的代码,将原有的BootClassLoader → PathClassLoader改为BootClassLoader → IncrementalClassLoader → PathClassLoader继承关系。

3.createRealApplication:

创建apk真实的application

4.monkeyPatchApplication

反射替换ActivityThread中的各种Application成员变量

5.monkeyPatchExistingResource

反射替换所有存在的AssetManager对象

6.调用realApplication的onCreate方法

7.启动Server,Socket接收patch列表

有代码修改时

1.生成对应的$override类

2.生成AppPatchesLoaderImpl类,记录修改的类列表

3.打包成patch,通过socket传递给app

4.app的server接收到patch之后,分别按照handleColdSwapPatch、handleHotSwapPatch、handleResourcePatch等待对patch进行处理

5.restart使patch生效

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容