Andfix热修复技术浅析

By吴思博

一、什么是热修复:

二、技术背景

三、当前主流的热修复方案比较

四、Andfix的介绍与实践(开源)

1原理

2基本使用

五、其他方案介绍

一、什么是热修复:

热修复(HotFix)是以补丁的方式动态修复紧急Bug,不再需要重新发布App,不需要用户重新下载覆盖安装的方式来实现代码的替换修改。

二、技术背景

(1)正常开发流程

从流程来看,传统的开发流程存在很多弊端:

1、重新发布版本代价太大

2、用户下载安装成本太高

3、BUG修复不及时,用户体验太差

(2)热修复开发流程

而热修复的开发流程显得更加灵活,优势很多:

1、无需重新发版,实时高效修复

2、用户无感知修复,无需下载新的应用,代价小

3、修复成功率高,把损失降到最低

三、当前主流的热修复方案比较:

热修复技术近期变得越来越热门,同时也出现了一些不同的解决方案,如阿里的AndFix(开源)、QQ空间补丁方案、以及微信的Tinker方案,但是它们的原理、适用场景都各有不同。我们项目中可以采用哪种方案,是我们比较关注的问题。

QQ空间超级补丁技术和微信Tinker支持新增类和资源的替换,在一些功能化的更新上更为强大,但对应用的性能和稳定会有的一定的影响;AndFix虽然暂时不支持新增类和资源的替换,对新功能的发布也有所限制,作为定位为线上紧急BUG的热修复的服务来说,还是比较好的,同时对应用性能不产生不必要的损耗,在热修复方面不失为一个好的选择。

四、Andfix的介绍与实践(定位:一个低成本快速接入的热修复第一方案)

Github:https://github.com/alibaba/AndFix

(1)AndFix是一个Android App的在线热补丁框架。使用此框架,我们能够在不重复发版的情况下,在线修改App中的Bug。AndFix就是“android Hot-Fix”的缩写。就目前来说,AndFix支持Android 2.3到7.0版本,并且支持arm与X86系统架构的设备。支持Dalvik与ART的Runtime。AndFix的补丁文件是以.apatch结尾的文件。

AndFix不同于QQ空间超级补丁技术和微信Tinker通过增加或替换整个DEX的方案,提供了一种运行时在Native修改Filed指针的方式,实现方法的替换,达到即时生效无需重启,对应用无性能消耗

AndFix实现过程:

对于实现方法的替换,在Native层操作,经过三个步骤:

下面以Dalvik设备为例,来分析具体的实现过程

对于Dalvik来说,遵循JIT即时编译机制,需要在运行时装载libdvm.so动态库,获取以下内部函数:

1 dvmThreadSelf( ):查询当前的线程;

2 dvmDecodeIndirectRef():根据当前线程获得ClassObject对象。

setFieldFlag

动态库会忽略非public属性的字段和方法,该操作的目的:让private、protected的方法和字段可被动态库看见并识别。

replaceMethod:

AndFix对ART设备同样支持,具体的过程与Dalvik相似。

该步骤是方法替换的核心,替换的流程如下:

优点:

1、BUG修复的即时

2、补丁包同样采用差量技术,生成的PATCH体积小

3、对应用无侵入,几乎无性能损耗

不足:

1、不支持新增字段,以及修改方法,也不支持对资源的替换。

2、由于厂商的自定义ROM,对少数机型可能暂时不支持。

(2)Andfix的基本使用。

1.在自定义Application中初始化,为了更早的修复应用中的bug。

package com.euler.andfix;

import android.app.Application;

import com.alipay.euler.andfix.patch.PatchManager;

public class MainApplication extends Application {

public PatchManager mPatchManager;

@Override

public void onCreate() {

super.onCreate();

//初始化patch管理类

mPatchManager = new PatchManager(this);

//初始化patch版本

mPatchManager.init("1.0");

//加载已经添加到PatchManager中的patch

mPatchManager.loadPatch();

}

}

2.如果有新的补丁需要修复,下载完成后,进行以下操作

//添加patch,只需指定patch的路径即可,补丁会立即生效

mPatchManager.addPatch(path);

3.当apk版本升级,需要把之前patch文件的删除,需要以下操作

//删除所有已加载的patch文件

mPatchManager.removeAllPatch();

我们也可封装成一个工具类

patch文件的生成

使用工具:apkpatch-1.0.3

原理:根据两个apk包,生成一个差异文件,就是所谓的补丁文件即patch文件。

命令: apkpatch.bat -f new.apk -t old.apk -o output1 -k debug.keystore -p android -a androiddebugkey -e android

-f :新版本

-t :旧版本

-o :输出目录

-k :打包所用的keystore

-p :keystore的密码

-a :keystore用户别名

-e :keystore用户别名密码

执行完命令,就会在输出目录中输出.apatch文件:

new-c293df7dbc23f11214fdd020ea78d3b8.apatch

:就是patch文件。

.apatch文件根目录内容:

META_INF

文件下内容:

PATCH.MF

文件内容:

注:Patch-Classes就是改动过的class.

客户端请求服务器接口(api),服务器根据用户传递的数据分析是否有需要修复的bug。如果有bug需要修复,就下载服务器指定的.apatch文件的链接,下载完后及时加载并修复,使用addpatch(path)方法,补丁会立即生效。

在Android Studio

dependencies {

compile 'com.alipay.euler:andfix:0.3.1@aar'

}

代码混淆(ProGuard)

-keep class * extends java.lang.annotation.Annotation

-keepclasseswithmembernames class * {

native ;

}

Q & A:

1、如何解决某些机型不兼容的问题?还有采用YunOS系统的?之前测试在ART模式机型上,偶现崩溃,不知采用了什么机制处理的?线上采用Andfix,会不会风险比较高?

ART的机型上暂时未出现崩溃的现象。对于机型的兼容性问题,采取的措施是做平台区间控制基本兼容,对于个别机型的问题,可以参考统计数据加入黑名单,与服务器约定协议,黑名单上的机型不走andifx流程。美聊线上实践暂时未出现不可控的问题

2、没有成功更新的情况下,会不会引起app的崩溃?

更新不成功不会引起崩溃

五、其他技术简介

android的类加载器分为两种,PathClassLoader和DexClassLoader,两者都继承自BaseDexClassLoader

PathClassLoader用来加载系统类和应用类。DexClassLoader用来加载jar、apk、dex文件.加载jar、apk也是最终抽取里面的Dex文件进行加载。

1、QQ空间超级补丁技术

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

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

但是有一个问题是,当两个调用关系的类在同一个DEX时,就会产生异常报错。在APK安装时,虚拟机需要将classes.dex优化成odex文件,然后才会执行。在这个过程中,会进行类的verify操作,如果方法中直接引用到的类(第一层级关系,不会进行递归搜索)和class都在同一个dex中的话,那么这个类就会被打上CLASS_ISPREVERIFIED,然后才会写入odex文件。所以,为了可以正常的进行打补丁修复,必须避免类被打上CLASS_ISPREVERIFIED标志,具体的做法就是单独放一个类在另外DEX中,让其他类调用。

其实就是两件事:

1、动态改变BaseDexClassLoader对象间接引用的dexElements;

2、在app打包的时候,阻止相关类去打上CLASS_ISPREVERIFIED标志。

手机QQ空间APK具体的实现:先进入程序入口QZoneRealApplication,在attachBaseContext中进行了两步操作:(1)修复CLASS_ISPREVERIFIED标志导致的unexpected DEX problem异常。(2)加载修复的DEX。

整体的流程图如下:

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

优势:

1、没有合成整包(和微信Tinker比起来),产物比较小,比较灵活

2、可以实现类替换,兼容性高。(某些三星手机不起作用)

不足:

1.不支持即时生效,必须通过重启才能生效。

2.为了实现修复这个过程,必须在应用中加入两个dex!dalvikhack.dex中只有一个类,对性能影响不大,但是对于patch.dex来说,修复的类到了一定数量,就需要花不少的时间加载。

3.在ART模式下,如果类修改了结构,就会出现内存错乱的问题。为了解决这个问题,就必须把所有相关的调用类、父类子类等等全部加载到patch.dex中,导致补丁包异常的大,进一步增加应用启动加载的时候,耗时更加严重。

2微信Tinker

微信针对QQ空间超级补丁技术的不足提出了一个提供DEX差量包,整体替换DEX的方案。主要的原理是与QQ空间超级补丁技术基本相同,区别在于不再将patch.dex增加到elements数组中,而是差量的方式给出patch.dex,然后将patch.dex与应用的classes.dex合并,然后整体替换掉旧的DEX,达到修复的目的。

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

优势:

1、合成整包,不用在构造函数插入代码,防止verify,verify和opt在编译期间就已经完成,不会在运行期间进行、

2、性能提高。兼容性和稳定性比较高。

3、开发者透明,不需要对包进行额外处理。

不足:

1、与超级补丁技术一样,不支持即时生效,必须通过重启应用的方式才能生效。

2、需要给应用开启新的进程才能进行合并,并且很容易因为内存消耗等原因合并失败。

3、合并时占用额外磁盘空间,对于多DEX的应用来说,如果修改了多个DEX文件,就需要下发多个patch.dex与对应的classes.dex进行合并操作时这种情况会更严重,因此合并过程的失败率也会更高。

小结

QQ空间超级补丁技术和微信Tinker的修复原理都基于类加载,在功能上已经支持类、资源的替换和新增,功能非常强大。但是也有非常多的问题。

A、多DEX带来的性能问题和影响

多DEX方案用来解决应用方法数65k的问题,现在Google也官方支持了MultiDex的实现方案。但是,这实在是应用因方法数超出而作出的不得已的下策,超级补丁技术和Tinker作为一种热修复的方案,平生给应用增加了多个DEX,而多DEX技术最大的问题在于性能上的坑,因此基于这种方案的补丁技术影响应用的性能是无疑的。

(a)启动加载时间过长

可以看到,超级补丁技术和Tinker都选择在Application的attachBaseContext()进行补丁dex的加载,即使这是加载dex的最佳时机,但是依然会带来很大的性能问题,首当其冲的就是启动时间太长。对于补丁DEX来说,应用启动时虚拟机会将patch.dex文件转换成odex文件,这个过程非常耗时。而这个过程,又要求需要在主线程中,以同步的方式执行,否则无法成功进行修复。就DEX的加载时间,大概做了以下的时间测试。

随着patch.dex的增加,在不做任何优化的情况下,启动时间也直线增长。

(b)易造成应用的ANR和Crash

正是尤其多DEX加载导致了启动时间过长,很容易就会引发应用的ANR。我们知道当应用在主线程等待超过5s以后,就会直接导致长时间无响应而退出。超级补丁技术为保证ART不出现地址错乱问题,需要将所有关联的类全部加入到补丁中,而微信Tinker采取一种差量包合并加载的方式,都会使要加载的dex体积变得很大。这也很大程度上容易导致ANR情况的出现。

除了应用ANR以外,多DEX模式也同样很容易导致Crash情况的出现。我们知道,超级补丁技术为了保证ART设备下不出现地址错乱问题,需要把修改类的所有相关类全部加入到补丁中,这里会出现一个问题,为了保证补丁包的体积最小,能否保证引入全部的关联类而不引入无关的类呢?一旦没有引入关联的类,就会出现以下的异常:

NoClassDefFoundError

Could not find class

Could not find method

出现这些异常,就会直接导致应用的Crash退出。所以,不难看出如果我们需要修复一个不是Crash的BUG,但是因为未加入相关类而导致了更严重的Crash,就更加的得不偿失。

如果我们仅仅就是开发一款app,没有大改动,不会热更全局变量,不会增加方法,那么AndFix框架是首选。

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

推荐阅读更多精彩内容