前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【连载】聊聊 APK(二)——Dex 热修复与 Classpath

【连载】聊聊 APK(二)——Dex 热修复与 Classpath

作者头像
程序亦非猿
发布2019-08-16 16:54:42
5880
发布2019-08-16 16:54:42
举报
文章被收录于专栏:程序亦非猿程序亦非猿

想进大厂,就关注「 程序亦非猿 」 时不时 8:38 推送优质文章,觉得有用,置顶加星标

船长导读:「聊聊 APK」系列由我好基友 Gemini 老师提供

上一篇文章《聊聊 APK —— 直接运行 Dex》我们知道了怎么在手机上运行 Dex,那么和 Dex 文件最相关的应用技术可能就是热修复了。

热修复与 Classloader

参照腾讯开源的 Tinker 和阿里的 DexPatch 的原理,我们知道对于现在对于 java 代码的热修复主要从 DexClassLoader 里面的 dexPathList 入手,这里应用的原理就是 classloader 双亲委派里对于加载后的类的缓存机制。

如果一个类在一个类加载器中加载过,就不会从其他类加载器中装载了。

Android 提供的 DexClassloader 是按提供的 dex 顺序找的,因此对于 java 代码的热修复变得很简单 —— 只要把想要被修复的 Dex 放到最前面,加载相关的类就好了,Tinker 和 DexPatch 当然还做了更多的事情,比如对 dex 进行 merge 之类的工作。这些我们就不细细讨论了,我们今天就简单的看一看,dex 的顺序影响是不是像热修复很多文章说的那样。

构造有问题的 Dex

我们首先要构造有问题的 Dex,我们写两个类,分别为Test.java,和HelloWorld.java,这里的HelloWorld类作为主入口,Test 类内容如下:

代码语言:javascript
复制
public class Test {
    public void run() {
        System.out.println("Bug!");
    }
}

那么打印一行 Bug! 字符串,代表里面有 Bug,我们需要修复。那么HelloWorld类自然是使用这个类了,它的代码如下:

代码语言:javascript
复制
public class HelloWorld {
    public static void main(String[] args) {
        Test test = new Test();
        test.run();
    }
}

这样,我们去调用 HelloWorld main 方法的时候,就能调用到 Test 类里面的 run 方法,默认输出一个Bug!,我们来做一下,编译依旧很简单,可以参照我上一篇文章,这里直接给出编译命令:

javac Test.java HelloWorld.java dx --dex -output=classes.dex Test.class HelloWorld.class

这样就产出了一个classses.dex,然后我们把它 push 到我们的手机上,在此之前,我们

adb push classes.dex /sdcard/

我们开始验证这个 dex 是否能有我们期望的结果 —— 输出Bug!

adb shell cd /sdcard/dalvikvm -cp classes.dex HelloWorld

看图可以看见非常顺利,我们构造了一个“有Bug”的 Dex,假设这个 Dex 目前存在于我们的 apk 里面,那我们如何使用一个新的 Dex 去覆盖我们的 Test.run 方法呢?

构造修复后的 Dex

很简单,首先,在相同的类里面,把我们的代码改了,比如这样,在 Test.java 中:

代码语言:javascript
复制
public class Test {
    public void run() {
        System.out.println("Fixed!");
    }
}

那么,我们把这个 Test 单独制成一个Dex文件,注意我们构造 Dex 的时候和上面不一样的地方:

 ~/javac Test.java HelloWorld.java  ~/dx --dex --output=new.dex Test.class

注意到,我们这时候和HelloWorld.java没有半毛钱关系,我们这时候构造出了一个新的new.dex,我们再把它 push 到手机上

adb push new.dex /sdcard/

可以看见我的 sd 卡下面有两个 dex,一个是新的new.dex,一个是老的classes.dex,这时候就要见证奇迹了。

应用热修复

查阅相关文档,我们可以查到-cp命令的用法是classpath1:classpath2,于是我们这里就这么用

dalvikvm -cp new.dex:classes.dex HelloWorld Fixed!

输出了Fixed!,这里再贴一个截图:

我们可以看见 cp 参数的不同,调用同一个类的main方法,输出不一样,这里就展示了如何利用dexPathList“欺骗” Android 系统进行热修复的最核心流程。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序亦非猿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 热修复与 Classloader
  • 构造有问题的 Dex
  • 构造修复后的 Dex
  • 应用热修复
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档