微信热补丁实现--Bspatch实现

前言

前不久看了一篇博文,讲述微信热补丁的,瞬间就被吸引了,于是决定花点时间研究下,挺不错的一篇文章,推荐大家去看一下,链接会附在本文末尾。

原理

我们首先来做一个假定:old.apk 为版本比较旧的apk(存在bug的版本),new.apk为新版的(修复bug的版本);假定他们发生bug的层面均和代码有关(暂时不考虑资源层面的替换)。
我们获取到两个apk中的classes.dex文件,分别命名为old.dex和new.dex,最终的目的是希望new.dex能够取代old.dex运行在old.apk的程序中。为此我们做了下面几步操作:

  1. 通过使用bsdiff工具,获取old.dex与new.dex的差量classes.patch(电脑端进行)。
  2. 在手机端获取到安装程序old.apk,解压缩获取到classes.dex,即old.dex。
  3. 在手机端通过bspatch工具(内部的.so)将old.dex和classes.patch 合成为new.dex。
  4. 在application的attachBaseContext中,构造一个DexclassLoader,将new.dex插入到BaseClassLoader的dexElements之前,使new.dex提前加载,来达到热补丁的效果。

实现过程中遇到的问题

  • 在程序端获取apk的路径 getApplicationInfo().sourceDir,本来想着我既然有apk路径的读写权限,我干脆直接从这个.zip文件中直接读取classes.dex文件即可,就没必要将其拷贝出来。但是在实现的过程中去Debug发现,其实自己并没有读取这个.zip文件的子目录内容的权限(为什么呢???慢慢调查下吧)。
  • 在编译dspatch.so的时候 遇到过"dlopen failed cannot locate symbol "signal" ",这个真的好坑,说下原因吧,是在stackoverflow中看到的,android-21之前,signal.so 是一个内联的功能。但是现在已经不再是了。如何解决呢?
    I.在使用ndk时在Application.mk中加入APP_PLATFORM:=android-15(:= 后面是你的编译的最低版本的sdk)。
    II.将你的编译时的sdk版本设置到android-21之前。
    具体链接如下:可恶的 cannot locate symbol。
  • 在实验的过程中,设想过直接加载替换了.dex的apk,这样的话那么所有的资源也就可以从这个dex中去获取了,但是发现其实是个特sb的问题,具体可以参考下这个链接:Apk 文件结构解析。既然我想要去替换整个资源文件,为什么不直接把old.apk 和new.apk做差量,获取到差量 的patch,然后通过old.apk 和patch合成新的apk,直接加载。(这个只是设想,后续会去验证一下)。

不足及问题

  • 去验证这个微信热补丁只是写了一个非常简单的demo,实现了基本的功能,但并未对复杂的问题去做深入验证,比如随着程序包的增长消耗的内存,时间,成功率等。
  • 现阶段可以验证的是不管是混淆还是非混淆,这个原理实现的热补丁都是可行的。这个应该比NuWa热补丁在生成补丁前做mapping简单些,毕竟一个是正向的,而另一个(微信)则是反向进行的,只是关系新旧包之间的差量。
  • 还要去研究下这个热补丁如果去加载资源文件让其能够生效,按道理是可行的。

github 链接

  • 非常简单的demo,可以学习下原理。这个是鄙人的github 链接 :https://github.com/shang1101/BspatchHotFix

参考链接

  • 微信Android热补丁实践演进之路

你可能感兴趣的:(微信热补丁实现--Bspatch实现)