**Android进阶宝典 -- AndFix热修复原理**
2023-09-21 03:58:54
前言
众所周知,Android应用在发布后,难免会出现bug,传统的解决方式需要发 版新的apk,用户需要从应用商店下载新的apk,这是一个非常耗时的过程。AndFix出现后,通过在 dex文件中加载修复包,在无需发 版新的apk的情况下,对修复这些bugs,使用AndFix,可以实现修复bug无缝、安全,无需等待发 版。
AndFix的原理是基于字节码修改,它需要将修复好的代码patch进dex文件,然后加载到内存中,然后反射的方式, 将修改好的代码替换当前的代码,以修复相关的bug。
了解AndFix的原理,首要的问题是了解Android平台下,Java虚拟机是如何处理方法的。Android平台下,手机厂商 为了满足Android应用的跨平台特性,需要采用兼容Java平台的虚拟机,常见的虚拟机有Java虚拟机和ART虚拟机。
而为了理解Java虚拟机和ART虚拟机的原理,需要了解,Java虚拟机是如何加载一个class文件,然后执行一个 method。
方法执行流程
1. Method 的查找过程
从指定的类路径上的各个类加载器,加载 指定的class文件,调用java.lang.Class 中的 forName,创建一个 java.lang.Class 的实例。
Class Class.forName(String className) throws ClassNotFoundException
{
...
}
然后通过 class 的 method 字段,获取所有的 method。
method是method修饰符,参数列表,返回值类型,异常表。
如果出现重复的,则选择符合下 述规则的那个method。
(1)与主参数表形 型完全相同。
(2)返回类型兼容。
得到最精确的一个 method。
2.Method 的调用过程
最精确的method 对应的methodHandle。
该methodHandle是一种类型,有的是个普通 指针,有的是个代码。
如果是指针,则直接执行对应method。
如果是代码,是类型methodHandle的call方法,
然后执行对应的method。
ARM指令集
Android ART 指令集
ARM指令集分为两种,ARM,THUMB。
其中THUMB 是 ARM 指令集的精简版,为了节约空间而创 造的,只有16位,而ARM指令集有32位。
LDM 高低 / LDMIA 高低 / LDMH 高低:
Load Multiple
多个寄存器的一个一个加载到内存
STM 高低 / STMD 高低 / STMM 高低:
Store Multiple
多个寄存器的一个一个存储到内存
LDDP 高低 / LDDP 高低:
Load Doubleword to register
从内存中加载双字到寄存器
SDDP 高低 / SDDP 高低:
Store Doubleword to register
把寄存器中的双字存储到内存
MRCC 高低 / MRC 高低:
Move Register to Register Conditional
将某一寄存器中的值放入到另一个寄存器
MRCCC 高低 / MRCCC 高低 / MBNTC 高低 / MNTEC 高低 /
Move Register to Register Conditional Carry
带进位条件的操作指令
BX 高低 / BLX 高低:
branch exchange
条件跳转和链式跳转
TBNZ 高低 / TBLZ 高低:
Test and Branch
Test
指令后面的条件可以选择通过什么标志 跳转。
CPSR 高低 / CPSRd 高低:
Change Processor Status Register
伪指令,执行指令后,将设置的CPSR状态,写入到CPSR寄存器中,低字节等同于 CPSR,高字节为0。
ArtMethod
ArtMethod 在 ARM 中,采用的是指针寄存器:
r0,返回参数和 返回值,采用R2,R3,...,R10
,传递参数。
ArtMethod 是个指针,这是一个函数指针,ArtMethod 也包含了 method 的相关信息,然后调用method时, 就是通过 ArtMethod 指针,读取 method 中的 methodPointer 字段,然后调用methodHandle,然后执行method。
当然ArtMethod 不止methodPointer,还有 MethodSignature、MemberType、ReturnType、 局部变量表、异常表、callsite等数据
实现 AndFix 热修复的基本原理
从Dex文件中加载修复包,加载到内存,然后反射,最后替换修复好的method。
通过So进行热修复,需要通过JNI,我们需要监听onClassLoading
这个方法,然后从Java进行反射
1. 加载修复包到 JVM
以dex进行传输,不能是apk,APP端的手机是 ART,通过LoadLibrary
,加载预先准备好的libAndFix.so
。
将其定位成可执行
,我们使用openDEX
,这 是 ART 提供的 api,调用这个 api,然后进行 读取
,通过dlopen
进行装载。
最后调用自己的 loadLibrary() 函数,将我们准备的修复包,放入 ArtMethod
。
2. 准备数据
需要检测出,修改的方法的 methodSignature
,然后将修复的方法中的 methodSignature
和 当前的方法 methodSignature
进行比较,用来检测到修复的方法。
Java 中通过反射,拿到 method,再拿到 methodSignature
,将 methodSignature
传 输到C,然后通过函数转化,拿到 ArtMethod
指针,用来检测出修复的方法。
3. 检查需要修复的方法
从 java 从 Java8 开始,可以对函数进行修改,现在需要把 java7 中的数据,迁移到 java8,这就需要读取到ArtMethod
。
然后把 ArtMethod
传到java,然后调用 callSite
,然后进行method 的替换。
4. method 的替换
所有的 method 在 java 中,全是方法指针,一个 method 可以有多个指针,指针会被被 So 通过 dlopen
装载,因为 ArtMethod 有一个 methodPointer
。
从 ArtMethod 中得到 methodPointer,它是个函数指针,它会 指向某个 函数,指向到 Arm
指令,这是一种汇编,直接改 Arm 指令中的函数指针,直接指向我们 修改好的 ArtMethod
中的函数指针,然后修改好后,最后记得发送消息,这样检测到,修复的方法已经完成。
后记
理解 AndFix
热修复原理,首要的问题就是了解,Java虚拟机
是如何加载一个 class文件,然后执行一个 method
。
推荐书籍
《Android 进阶宝典》,《深入理解Java虚拟机》。