关于Android APP在线热修复bug方案的调研(一)(AndFix)

原创 2015年12月15日 16:38:12

调研背景:

     App发布出去后,如果发现有紧急或重要bug如何进行修复呢?

     重新发布一版APK?但这样代价太大....

      那么有没有一种方案能够不用更新整个APK,而只把服务器上的很小的补丁文件下载下来进行修复bug呢?

      本文的调研也正是为了解决该问题。


几种解决方案对比:

      下面是找到的3款比较火的开源解决方案,分别都是利用不同原理实现的:

名称

优点

缺点

适用场景

实现原理与下载

DynamicAPK

1.支持插件化开发,并且Plugin APK能够访问Host APK的资源

1.需要修改aapt工具,改变原来的编译流程。

2.不支持Hot fix(官方介绍有文字提到支持,但只是load的时候考虑了下,还有很多工作没有实现)

 

适用于Plugin开发

【实现原理】

这是携程网开源的,Multidex+AAPT编译流程改造。参考:http://www.infoq.com/cn/articles/ctrip-android-dynamic-loading?utm_campaign=infoq_content&



【源码下载】

https://github.com/CtripMobile/DynamicAPK

 

AndFix

1.Mexdex方案相比,性能要好些。(Multi Dex需要修改所有classclass_ispreverified标志位,导致运行时性能有所损失)


2.
支持ARTDalvik

3.
支持6.0

1.跳过了类初始化,对于静态或者构造函数或者class.forname()的处理可能会有问题

在线修复bug

【实现原理】

阿里的开源项目,原理是函数Hook。GitHub上有介绍。



【源码下载】

https://github.com/alibaba/AndFix

Nuwa

(HotFix/DroidFix)

 

1.兼容性比AndFix(Multi dex方案,没有static的问题)

2.支持ARTDalvik



3.支持6.0

 

 1.编译完成java代码后,需要遍历修改class文件,插入代码,防止class被打上class_ispreverified标志,这会导致运行性能降低


 

在线修复bug

 【实现原理】

Multidex的动态加载原理,参考:http://bugly.qq.com/blog/?p=781



【源码下载】
https://github.com/jasonross/Nuwa


 结合我的目标,目标锁定在第2个与第3个。


AndFix的操作使用】

选择第二个AndFix来进行研究:

第一步:模拟发布APK:

使用自带的sample中的列子,修了下onCreate()中的代码,如下:



安装运行bug.apk,如预期输出如下Log:


第二步:现在App发布出去后有Bug啦,我们要改变onCreate()的输出,赶紧开始制作patch.....

修改输出代码为如下:



编译出fix后的APK,这时需要使用AndFix/tools/下面的apkpatch这个工具来制作patch(补丁)文件。

工具所在目录:


工具使用说明:

ApkPatch v1.0.3 - a tool for build/merge Android Patch file (.apatch).
Copyright 2015 supern lee <sanping.li@alipay.com>

usage: apkpatch -f <new> -t <old> -o <output> -k <keystore> -p <***> -a <alias> -e <***>
 -a,--alias <alias>     alias.
 -e,--epassword <***>   entry password.
 -f,--from <loc>        new Apk file path.
 -k,--keystore <loc>    keystore path.
 -n,--name <name>       patch name.
 -o,--out <dir>         output dir.
 -p,--kpassword <***>   keystore password.
 -t,--to <loc>          old Apk file path.

usage: apkpatch -m <apatch_path...> -k <keystore> -p <***> -a <alias> -e <***>
 -a,--alias <alias>     alias.
 -e,--epassword <***>   entry password.
 -k,--keystore <loc>    keystore path.
 -m,--merge <loc...>    path of .apatch files.
 -n,--name <name>       patch name.
 -o,--out <dir>         output dir.
 -p,--kpassword <***>   keystore password.

下面就开始使用这个命令来制作patch文件:

执行如下命令:
apkpatch.sh -f fixed.apk -t bug.apk -o out -k sig -p 123123 -a test_sig -e 123123

命令的输出:
add modified Method:V  onCreate(Landroid/os/Bundle;)  in Class:Lcom/euler/andfix/MainActivity;


第三步:到此补丁文件制作好了,就可以通过网络等渠道推送到手机上。

查看out目录,一共有3个,会在后面进行解释:


这里的.patch文件就是我们需要的,把它push到手机:



重起刚才的APP,观看Log输出时否改变了:


^_^,补丁成功了,而且这个文件也才3KB多点哦,非常适合在线修复bug~~~~

-rw-rw-r-- 1 yanchen yanchen 3468 12月 15 18:32 out/fixed-07d99a18833f092518fbb041c793e53b.apatch


AndFix的源码分析

============================================================================================================================

Patch的制作流程现在知道了,下一步就准备进入Code层面的分析,探究它的内部实现原理。

============================================================================================================================


首先来看Patch制作原理:

制作patch会用到apkpatch这个工具,而它会调用apkpatch-1.0.3.jar这个文件。反编译这个jar包,发现在制作patch时,它会进入ApkPatch的doPatch()这个函数完成的。


进入doPatch函数看看:



这个函数逻辑挺清晰的,一共就这4个步骤。

第一步是diff,它会比对两个APK的差别,来看看它的代码是如何实现的:


这个函数会提取fixed.apk与bug.apk中的classes.dex文件,然后通过2个for循环,来对比每个class文件中的字段与函数是否完全一致。


那么字段和函数又是如何对比的呢?

我们来看看compareMethod()函数内部实现:


原来对比函数时会看两个是否有函数实现,有的话就会看两个函数的函数体是否一致,代码如下:


如果不一致就会添加到一个叫info的HashSet变量中。

而比对字段主要看字段的初始值是否一样,代码如下:



总结:

通过上面的步骤就比对出了两个APK中的classes.dex中差别,并且将有差别的文件保存在了info变量中。


接下来进入第二步,开始进行buildCode(),这步的目的是将info中保存的文件写到.smali文件中,然后再打包成一个dex文件。


比如下面的是我的demo产生的smali文件:




在生成的smali函数中,它会添加一个自定义的Anotation,叫MethodReplace



到此,第二个步骤也就完成了,它一共产生2个文件:



接下来进入第三个步骤,调用build()函数,这步会将上一步产生的dex文件写入到一个jar文件,并进行签名,代码如下:


PatchBuilder的代码如下:


所以第三步完成后,会产生一个叫作diff.apatch的jar文件。

接下来进入最后一步,调用release()函数,也就是通过它产生最终的patch文件。

看看release()中都做了些什么事情:


主要是将第三步生成的diff.apatch文件重命名为name-md5-.patch格式的文件


到此,patch的制作原理也就告一段落了,主要就是提取两个APK中的classes.dex,对比他们中的class文件是否有区别,将有区别的提取出来打包到.apatch文件中。

最终的产物如下:


============================================================================================================================

以上是Patch的制作流程分析,下一下我们再来看看客户端是如何将这个patch文件打入自己的APK中的。

============================================================================================================================


要使用这套框架,客户端只需在Application的onCreate()中加入如下的代码:


那我们就来看看这几行代码到底会做什么事情。

init()函数主要工作时载入files/apatch/目录下的.apatch文件,代码如下:


initPatchs()代码如下:

它读取mPathDir目录下的所有.patch文件,并将起添加到一个叫mPatchs的HashSet变量中。

这是mPatchDir的初始值:


看来这个函数的目的就是在启动的时候,读取所有本地的patch文件。

读取完毕后调用loadPatch()来进行运行时的APK修复,代码如下:


fix()函数的代码如下:


它会加载.apatch文件中class,然后再调用fixClass(),继续往下看:


会读取自定义的Anotation MethodReplace,通过它获取到class名字与method名字,进行替换。

在前面的分析中也介绍过MethodReplace的内容格式,可参考如下:


而在进行Replace Method是,是在Native层做:


在JNI的代码中,支持Dalvik与ART,这时它的代码结构:


其修复原理就是从内存中找出原来函数指令指针,让它指向新的函数地址:



上面的meth变量便是我们bug.apk中的函数的句柄,target便是.aptach文件中函数的句柄。

而insns是函数指令地址的指针,解释如下:



到此函数替换的原理就水落石出了,就是函数Hook。

很犀利的做法。


【总结】

所以总结一下补丁执行的原理就是:

在运行时,读取patch文件中的函数,将它的函数指令地址赋给APK中的函数。

这样不就等于替换了原来的函数么?那么bug也就可以被消除了。。。

当然这一切都是在内存中进行的,不会对本地的APK有任何影响。

AndFix(续) - MultiDex

前言: 刚跌进了几个坑,又呛过了几条河,怎么程序bug它就这么多….问题描述: 之前集成了AndFix,一路毫无障碍的过去了,可以看我的Android 热修复 - AndFix 使用心得,这是基本...
  • cjh_android
  • cjh_android
  • 2016年07月22日 17:21
  • 1272

关于Android APP在线热修复bug方案的调研(二)(MultiDex的原理分析---Nuwa)

通过上一篇的分析,目前bug在线热修改的主要两套框架AndFix与Nuwa. 上篇文章也对AndFix的机制进行了分析。 那么这两套框架该如何选取呢?从目前的测试来看,Nuwa的支持似乎要比AndFI...
  • XXOOYC
  • XXOOYC
  • 2015年12月16日 17:21
  • 2908

Android 热补丁动态修复框架小结

转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/49883661; 本文出自:【张鸿洋的博客】 一、概述最新githu...
  • lmj623565791
  • lmj623565791
  • 2015年11月17日 10:01
  • 125515

Android热修复AndFix混淆后热修复失败,无效

这几天一直在研究热修复,对比了多个框架,最终因为是Eclipse开发,所以把重心渐渐转移到AndFix上面。 AndFix地址:https://github.com/alibaba/AndFix ...
  • y97524027
  • y97524027
  • 2016年09月18日 10:55
  • 1648

Android热修复框架AndFix原理解析及使用

最近腾讯弄出一个Tinker热修复框架,那么本文先不介绍这个框架,而是先来介绍一下阿里的一个热修复框架AndFix,这个框架出来已经很长时间了,但是看网上没有太多非常详细的讲解,这里就来做一次分析。正...
  • jiangwei0910410003
  • jiangwei0910410003
  • 2016年11月24日 08:51
  • 12459

Alibaba-AndFix Bug热修复框架原理及源码解析

小憩之后,继续为你解读AndFix热修复框架,呵呵。上一篇Alibaba-AndFix Bug热修复框架的使用已经介绍了AndFix的使用,这篇主要介绍AndFix原理以及源码解析。AndFix原理A...
  • qxs965266509
  • qxs965266509
  • 2015年11月13日 13:50
  • 35841

Android中热修复框架AndFix原理解析及案例使用

编码美丽 2016-11-21 17:51 一、前言 最近腾讯弄出一个Tinker热修复框架,那么本文先不介绍这个框架,先来介绍一下阿里的一个热修复框架AndFix,这个框架出来已经很长时...
  • u011277123
  • u011277123
  • 2016年11月22日 09:44
  • 1691

Android热修复:Andfix和Hotfix,两种方案的比较与实现

Andfix和hotfix是两种android热修复框架。android的热修复技术我看的最早的应该是QQ空间团队的解决方案,后来真正需要了,才仔细调查,现在的方案中,阿里有两种Dexposed和An...
  • yuankundong
  • yuankundong
  • 2016年05月10日 17:44
  • 3929

Android热修复之AndFix使用教程

AndFix的github地址 AndFix 全称Android hot-fix,是alibaba的Android热修复框架,支持Android 2.3到6.0的版本,支持arm与X86系统架构,...
  • gaobaoshen1
  • gaobaoshen1
  • 2016年08月04日 15:24
  • 573

Alibaba-AndFix Bug热修复框架的使用

AndFix这篇主要介绍alibaba的AndFix项目的使用,下一篇介绍 AndFix原理及源码解析。Github:https://github.com/alibaba/AndFixAndFix介绍...
  • qxs965266509
  • qxs965266509
  • 2015年11月13日 10:40
  • 24808
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:关于Android APP在线热修复bug方案的调研(一)(AndFix)
举报原因:
原因补充:

(最多只允许输入30个字)