Android热修复方案研究

一、概述

  以前对Android 的热修复方案有一些了解,知道几个有名的开源方案,原理大概理解,但是没有整理汇总一下,上周听了玉斌大哥在公司做的分享后,感受颇多觉得写篇博客记一下,不能浪费。

  热修复是指在不发新版的情况下修复线上的紧急 bug,长久以来做移动开发的人员都羡慕做后端或者做 web 前端的人员可以随时发布来修复 bug。那么 移动开发有没有这样的方案呢?

Hybrid

如:PhoneGap、国内的 AppCan。本质还是利用了 Web 开发在更新上的优势,但体验不如 Native。

ReactNative

像Web一样可以随时发布,又有原生的体验,所以这个方案优势挺大,有很多项目都在尝试。

Native HotFix

可以不用发新版本,直接下发补丁包修复 bug,纯原生体验。

iOS有JSPatch、Android 有 AndFix、Nuwa、DroidFix 、HotFix等

二、Android Native HotFix

下面按照原理分类为

(一) Dex分包方案(QZone的方案)(如 Nuwa、DroidFix、HotFix、RocooFix)

  原理:如果多个 dex 里有相同的class,那么虚拟机会优先使用最先加载的 dex 中的 class。所以将有问题的类打包到一个新dex(pathc.dex),然后下发给 app,app 启动时将该patch.dex插入到其他 dex 前面优先加载。就达到了 替换有问题 class 的目的。

这里有两个难点:

1. 改变dex加载顺序

2. class_ispreverified

错误信息:java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation

原因

  dex转化成odex时会执行dvmVerifyClass进行类的校验,如 B的引用和B都在一个 dex 里,则 B 会被打上class_ispreverified标记,但是我们优先加载 A’,A’和B在两个不同的 dex,但 B 却打上了class_ispreverified标识所以就报错了。

  两个相关联的类在不同的dex中并且有class_ispreverified就会报错,谷歌MultiDex拆分dex的时候就会处理这种情况如果A 和 B 不在同一个 Dex 就不会给 B标记class_ispreverified。

  但我们是热修复,patch.dex 是事后打的 dex,class.dex已经安装的用户手机里了,所以我们无法修改 B 的标识。

解决方案:

我们发布版本打包时,将所有的类都引用一个单独dex的一个类,这个所有的类都不会标记class_ispreverified了,当然这也就失去了class_ispreverified的意义,会有性能上的影响。

更新:还有一个巧妙的方案来防止class_ispreverified,就是在工程里放入一个android.jar 已经存在的类,这样会导致multiple class declarations 从而不会再对class 校验。比如使用com.android.internal.util.Predicate,这样类的特点是特别简单没有额外引用,然后它从android api 8 就存在了。

QZone 安卓App热补丁动态修复技术介绍

深度理解Android InstantRun原理以及源码分析

(二)smali diff方案(阿里的方案)(以 AndFix为例)

1. 原理

2. 方法替换(AOP)

  搞过 Android Aop 的同学知道,我们可以在执行一个方法的前插入另一个方法,运用这个思路,我们可以把有 bug 的方法替换成我们下发的新方法。

下边是 AndFix 使用 JNI hook 方法的一段代码,供大家理解。另一个实现AOP 的开源方案

dexposed

Android AOP 常用有的方法有 JNI HOOK 和 静态织入。

常用的静态织入的库有:

1、APT 是代码生成,java文件 生成 java文件。使用的annotation类型是SOURCE.

2、Aspectj是静态织入。静态织入:指在编译时期就织入,即:编译出来的class文件,字节码就已经被织入了。AspectJ就是一个编译器,把java文件编译成想要的class文件。使用的annotation类型是SOURCE.

3、ASM或者Javassist或者dexmaker 是Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。使用的annotation类型是class.

注:

cglib底层采用ASM字节码生成框架,实现动态代理实现AOP

cglib在android中是不能使用的。使用dexmaker框架来仿照动态生成.dex文件,实现cglib的动态代理功能

3. ApkPatch tool

  AndFix 提供了一个打包 patch 的工具,这个工具将旧Apk和新Apk做 diff 得出一个patch apk。

熟悉增量更新的同学应该知道,增量更新也是做 diff 求增量包,但是他是在字节码层面上求增量包,增量包+旧 apk 合并成新 apk。

  而ApkPatch是通过对比两个 apk 反编译后的 smali 文本文件来求 diff 的。所以他是从 class 层面上求 diff。得到的patch就是标准的 dex 包。 该 dex 可直接被 load。

4. 以前注意事项

一个 patch 包要修复哪些类的哪些方法,这个路径信息会被打包到 patch.apk 的META-INFO里

patch.apk在打包时要使用相同的签名。

混淆的情况:打包 patch.apk 时要使用主apk混淆时导出的 mapping 文件,防止主apk和patch.apk 由于混淆而无法对应相应的类和函数。

目前 apkpatch 没有开源,还有一些小 bug,如不支持 mulitdex。虽然没有开源但还是有方法修复的,比如反编译导出源码、还有 javasist 神器。具体怎么修复以后再说,也可能官方会修复。

(三)微信的方案

AndFix 由于影响正向开发过程(只能修改方法、不能修改 field、不能新增类等问题)、库本身难于维护以及发现的莫名其妙的 bug(不同rom对dex的校验机制不一致)。

nuwa 仅支持更新 Java 代码,不能更新资源和 so 文件。

全量替换新的Dex。即我们完全使用了新的Dex,那样既不出现Art地址错乱的问题,在Dalvik也无须插桩。当然考虑到补丁包的体积,我们不能直接将新的Dex放在里面。但我们可以将新旧两个Dex的差异放到补丁包中,最简单我们可以采用BsDiff算法。

附《Android核心知识笔记2020》分享

前段时间我和圈子里的几位架构师朋友一起闲聊时的突发奇想,我们在学习Android开发的时候或多或少也受到了一些前辈的指导,所以想把这份情怀延续下去。三个月后,这套资料就出来了,需要这份资料的朋友加Android学习交流群1049273031即可获取。

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

推荐阅读更多精彩内容