阿里 Dexposed 热修复原理

前言

Andfix 算是热修复方案中,native流派的典范了。在讲解Andfix之前,我们首先了解一下Dexposed,Andfix 是在Dexposed的基础上演进的。

Dexposed介绍

阿里手淘团队基于 Xposed 研发出来的 AOP 框架,方法级粒度,可以进行 AOP 编程、插桩、热补丁、SDK hook 等功能。它的热补丁方案原理图大致如下::
阿里 Dexposed 热修复原理

从上图中我们可以看出,它的主要原理是将 Java method 改变为 native, 并且将这个方法的实现链接到一个通用的 Native Dispatch 方法(即一个公共分发函数上)来修改方法加载逻辑以实现热补丁功能。
和 Xposed 不同的是,Xposed 通过劫持 zygote(须 root ),而 Dexposed 则是通过劫持 Java method (而非劫持 class loader)。我们可以用它来热替换某个导致崩溃的方法,此外手淘还用它作性能监控。这主要得益于无侵入式的方法调用 Befor 和 After 事件,能够让我们很好的记录和分析一个方法的调用时间。开源项目 promeG/XLog 就是基于 dexposed 实现的方法调用 logging。
但是它有个硬伤:不支持 art 平台。因此在Android L推出后,2015年起它就逐渐淡出了广大开发者的视线了。不过它的思想还是值得我们借鉴的。

AOP介绍

AOP(Aspect Oriented Programming),也就是面向方面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP一般应用在日志记录,性能统计,安全控制,事务处理,异常处理等方面,它的主要意图是将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

Dexposed 示例

我们可以利用 Dexposed 在应用中所有的 Activity.onCreate(Bundle) 函数调用之前和之后增加一些处理:

阿里 Dexposed 热修复原理

从代码我们可以看到入口是DexposedBridge.findAndHookMethod方法,详情细节就不过多阐述了,有兴趣的同学可以自行阅读dexposed的开源项目源码,GitHub地址是:https://github.com/alibaba/dexposed

这里给出大致流程:
1. 调用DexposedBridge.findAndHookMethod,进入到DexposedBridge类(Java层逻辑)
2. 通过XposedHelpers.findMethodExact找到要hook的java方法,然后再用hookMethod进行真正的hook。
3. hookMethod方法先把hook成功后的callback、要hook的方法的参数和返回值类型保存到AdditionalHookInfo中,把它作为参数传给hookMethodNative。hookMethodNative是一个native方法,它的第3个参数slot表示该Method在class的方法表中所处的位置,在native的实现中会用到这个slot。
4. hookMethod 方法中调用hookMethodNative,执行Native层方法。
6. com_taobao_android_dexposed_DexposedBridge_hookMethodNative (JNI入口),把Java层传递的信息构造成DexposedInfo信息,然后设置hook方法accessFlags设置为ACC_NATIVE ,即native方法,并且指定nativeFunc函数 ( 为什么会这么做: method的结构体表示了一个Java层函数, 而其中的accessFlags属性如果是ACC_NATIVE , 则dvm在调用原Java函数的时候, 会转向调用属性nativeFunc 所指向的函数)。
7. native层用dvm的各种函数来操作Method的指针和对象来控制函数,最后通过反射调用handleHookedMethod回到Java层的方法handleHookedMethod,回到Java世界。

下一篇是 Andfix 方案原理分析篇,后续整理好会发出来。