前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Dex热修复原理

Dex热修复原理

作者头像
ppjun
发布于 2018-09-05 03:58:47
发布于 2018-09-05 03:58:47
1.2K00
代码可运行
举报
文章被收录于专栏:ppjun专栏ppjun专栏
运行总次数:0
代码可运行

市场上热修复有两种一种是基于multidex的更新修复(比如tinker),另外一种是native hook(比如dexposed),tinker这种是反射获取dexelements数组,修改dex加载顺序。今天我们主要介绍dex这种。 热修复包括两个部分

  1. 从远程端下载修复好bug的补丁包
  2. 客户端安装补丁包,加载补丁包的类。

使用android�类加载器,在类没被加载到模拟器前(一般在application热修复,如果类已加载,再去记载相同的类就无效了)然后先加载补丁dex,再去加载原来的app里面的dex,因为加载过的类 不会被加载第二次,从而做到热修复。

1. 类加载器

android的类加载器分为PathClassLoader和DexClassLoader.他们两者之间的区别就是

  1. PathClassLoader只能加载安装到手机里面的dex(比如data/app/包名里面的dex)
  2. DexClassLoader 可以加载任意目录下的dex/jar/apk/zip.

下面我们从源码看看他们到底有什么不同

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class PathClassLoader extends BaseDexClassLoader {
   
    public PathClassLoader(String dexPath, ClassLoader parent) {
        super(dexPath, null, null, parent);
   }

   
   public PathClassLoader(String dexPath, String libraryPath,
           ClassLoader parent) {
        super(dexPath, null, libraryPath, parent);
}


//分割线
    public class DexClassLoader extends BaseDexClassLoader {
        public DexClassLoader(String dexPath, String optimizedDirectory,
          String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
   }
}

从代码可以看到两个classloader都继承了BaseDexClassLoader 调用了父类的构造方法,dexclassloader多传入了一个optimizedDirectory文件,然后从注解可以看到optimizedDirectory参数是dex输出的文件。接下来我们再看basedexclassloader里面做了什么骚操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class BaseDexClassLoader extends ClassLoader {
     private final DexPathList pathList;
 public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(parent);
       this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
   }

   @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
       Class c = pathList.findClass(name, suppressedExceptions);
        if (c == null) {
            ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
           for (Throwable t : suppressedExceptions) {
               cnfe.addSuppressed(t);
           }
           throw cnfe;
        }
        return c;
    }

    @Override
    protected URL findResource(String name) {
        return pathList.findResource(name);
    }

    @Override
    protected Enumeration<URL> findResources(String name) {
        return pathList.findResources(name);
   }

   @Override
    public String findLibrary(String name) {
       return pathList.findLibrary(name);
   }
   ....

BaseDexClassLoader的构造参数分别是

  1. 一系列的补丁包路径
  2. 补丁包输出路径
  3. 加载用到库的路径,比如c 那些native库
  4. 父加载器

其中DexPathList通过这四个参数完成初始化。最后通过findclass方法 里面的DexPathList.findClass来返回类。

2. DexPathList源码

接着看DexPathList源码里面做了什么 首先看构造函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
            String libraryPath, File optimizedDirectory) {
                //省略参数的判断

this.definingContext = definingContext;
       ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
       this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
                                         suppressedExceptions);
       if (suppressedExceptions.size() > 0) {
            this.dexElementsSuppressedExceptions =
                suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]);
        } else {
            dexElementsSuppressedExceptions = null;
        }
       this.nativeLibraryDirectories = splitLibraryPath(libraryPath);

}

从代码可以看到给classloader赋值,创建一个异常的list,给dexelements赋值,这里的dexelements是一个数组。来看看splitDexPath到底做什么了。 看到splitAndAdd方法会根据:来截取字符串,就是多个dexpath之间用:分割,然后变成file,被加进去List<File> flies里面。最后看makeDexElements方法, 遍历files,首先判断是否文件夹,是的话全部加进去elements,最后装转成ELement数组。 最后在DexPathList的findclass方法,将Element的数组每个Element对象的dex加载成class。

所以我们在什么时候插入补丁包的dex呢,就在Dexpatchlist类的findclass方法里面。将补丁的Elements数组加上原来的Elements数组,一起循环获取dex返回class。我们可以通过反射去获取elements数组。然后合并数组。调用findclass方法。以上就是multidex热修复的原理。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.02.27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
手动实现Android热修复
周一发布了新版本,当天晚上用户就为app未测试到的bug发飙了,恩,很快就找到了问题所在,一个容易疏忽的空指针。虽然只是一个小小的bug但是不修复是很影响用户体验的啊,如果要重新修复上线,波及范围太广了,所有用户又要重新下载。 我们可以让这个bug“偷偷”的修复
用户1269200
2018/07/30
7840
手动实现Android热修复
浅谈Android热修复的前因后果与实现原理。
说到这个就躲不过一个关键点 ClassLoader(类加载器) ,所以我们先从Java开始。
Petterp
2022/02/09
1K0
浅谈Android热修复的前因后果与实现原理。
Android动态加载入坑指南
曾几何时,国内各大公司掀起了一股研究Android动态加载的技术,两年多过去了,动态加载技术俨然成了Android开发中必须掌握的技术。那么动态加载技术是什么呢,这里谈谈我的个人看法,如有雷同,纯属偶然。 什么是动态加载技术 对于动态加载的概念,没有一个权威的定义,参考网上的解释,我们举一个例子,动态加载代码就是通过在运行时加载外部代码(磁盘,网络等)改变程序行为的技术(感觉有点像装饰者模式)。主要目的是为了达到让用户不用重新安装APK就能升级应用的功能。 为了加深大家对这种概念的理解,我们结合pc端来说说
xiangzhihong
2018/02/05
2.3K0
Android动态加载入坑指南
Tinker原理
Tinker采用的是下发差分包,然后在手机端合成全量的dex文件进行加载。而在build.gradle配置中的tinkerPatch
老马的编程之旅
2022/06/22
6630
Tinker原理
Android类加载之PathClassLoader和DexClassLoader
任何结论在没有经过实际检验之前都不能够确定一定没问题。三年前写的文章回过头来发现有些部分内容是有问题的(PS:这的确比较尴尬),再次对结果进行验证之后重新修改了之前的结论。幸亏文章阅读量不是很多,希望被误导的同学能够在其他地方得到正确结论。
静默加载
2020/05/29
2.6K0
【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexPathList 构造函数分析 | makeDexElements 函数分析 )
上一篇博客 【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | 类加载器构造函数分析 | DexPathList 引入 ) 中 , 分析了 DexClassLoader 构造函数的调用流程 , 在构造函数中执行的核心操作就是 在 BaseDexClassLoader 的构造函数中 初始化了 DexPathList 实例对象 ;
韩曙亮
2023/03/30
3160
浅谈Android热更新的前因后果
Android Studio2.0时,新增了一个 Instant Run的功能,而各大厂的热修复方案,在代码,资源等方面的实现都是很大程度上参考了Instant Run的代码。所以可以说 Instant Run 是推进Android 热修复的主因。
Rouse
2021/07/08
1.7K0
浅谈Android热更新的前因后果
Android热修复原理解析
通过上面几个类的关系,和类的查找过程,我们可以发现最终是通过遍历 DexPathList的 dexElements数组进行类的查找加载,当找到类就返回;
用户1205080
2019/03/05
7390
热修复
热修复有两种方式:一方面是阿里系为代表的底层方法替换,另一方面是以腾讯系为代表的类加载方案。前者支持立即生效,但是限制比较多;后者必须冷启动生效,相对较稳定,修复范围广。之前分析过微信的热修复框架 Tinker 即属于后者, 《Tinker 接入及源码分析》。本篇文章主要分析以 AndFix 为代表的底层方法替换方案,并且实现了《深入探索 Android 热修复技术原理》中提到的方法替换新方案。
用户9854323
2022/06/25
9720
热修复
【Android 逆向】Dalvik 函数抽取加壳 ② ( 类加载流程分析 | ClassLoader#loadClass 分析 | BaseDexClassLoader#findClass 分析 )
分析类加载器的 双亲委派机制 ; 在 ClassLoader.java 类加载器中 , 双亲委托机制如下 :
韩曙亮
2023/03/30
2550
Android ClassLoader流程解读并简单方式实现热更新
ClassLoader在启动Activity的时候会调用loadClass方法,我们就从这里入手:
曾大稳
2018/09/11
1.3K0
Android:这是一份全面&详细的 热修复 学习指南
注:需完成上述步骤(防止类被打上 CLASS_ISPREVERIFIED 标记),再实现补丁
Carson.Ho
2019/03/11
4200
Android:这是一份全面&详细的 热修复 学习指南
【Android 热修复】热修复原理 ( 类加载分析 | 分析 PathClassLoader 源码 | 分析 BaseDexClassLoader 源码 | 分析 PathDexList 源码 )
PathClassLoader 是 Android 平台的类加载器 , 继承了 BaseDexClassLoader ;
韩曙亮
2023/03/29
4970
Android中实现热补丁动态修复详析
热修复已经不是什么新的话题,目前仍然对它的讨论很火,本文是一篇动态修复的实践篇,以腾讯HotFix为蓝本,带你体验热修复之旅。
开发者技术前线
2020/11/23
1K0
Android中实现热补丁动态修复详析
【Android 热修复】热修复原理 ( 合并两个 Element[] dexElements | 自定义 Application 加载 Dex 设置 | 源码资源 )
在 【Android 热修复】热修复原理 ( 加载 Dex 文件到内存中 | DexClassLoader | PathClassLoader | 反射 Element[] dexElements ) 博客中已经将 系统加载的 Dex 文件对应的 Element[] dexElements 通过 PathClassLoader 类加载器获取到了 , 同时修复包对应 Dex 文件 Element[] dexElements 通过 DexClassLoader 类加载器获取到了 ;
韩曙亮
2023/03/29
3240
Android插件化学习之路(二)之ClassLoader完全解析
Java代码都是写在Class里面的,程序运行在虚拟机上时,虚拟机需要把需要的Class加载进来才能创建实例对象并工作,而完成这一个加载工作的角色就是ClassLoader。
老马的编程之旅
2022/06/22
5950
【Android 安全】DEX 加密 ( 多 DEX 加载 | 65535 方法数限制和 MultiDex 配置 | PathClassLoader 类加载源码分析 | DexPathList )
在 Android 开发中 , 尤其是项目比较大时 , 或引入的依赖库过多 , 一般的项目后期都会遇到 如下问题 , 整个工程的方法数超过了
韩曙亮
2023/03/28
9490
【Android 安全】DEX 加密 ( 多 DEX 加载 | 65535 方法数限制和 MultiDex 配置 | PathClassLoader 类加载源码分析 | DexPathList )
热修复框架HotFix源码解析
讲起 Android 的热修复,相信大家对其都略知一二。热修复可以说是继插件化之后,又一项新的技术。目前的 Android 热修复框架主要分为了两类:
俞其荣
2022/07/28
6230
热修复框架HotFix源码解析
Android:这是一份全面&详细的 热修复 学习指南
热补丁修复技术在Android 圈非常火,大量的热补丁方案开始大量涌现 本文将为你全面介绍热补丁的相关知识(原理、主流库使用),希望您会喜欢
Android技术干货分享
2019/03/27
4410
Android:这是一份全面&详细的 热修复 学习指南
【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 使用反射获取方法创建本应用的 dexElements | 各版本创建 dex 数组源码对比 )
参考 : 4.4.4_r1/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
韩曙亮
2023/03/28
2.2K0
推荐阅读
手动实现Android热修复
7840
浅谈Android热修复的前因后果与实现原理。
1K0
Android动态加载入坑指南
2.3K0
Tinker原理
6630
Android类加载之PathClassLoader和DexClassLoader
2.6K0
【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexPathList 构造函数分析 | makeDexElements 函数分析 )
3160
浅谈Android热更新的前因后果
1.7K0
Android热修复原理解析
7390
热修复
9720
【Android 逆向】Dalvik 函数抽取加壳 ② ( 类加载流程分析 | ClassLoader#loadClass 分析 | BaseDexClassLoader#findClass 分析 )
2550
Android ClassLoader流程解读并简单方式实现热更新
1.3K0
Android:这是一份全面&详细的 热修复 学习指南
4200
【Android 热修复】热修复原理 ( 类加载分析 | 分析 PathClassLoader 源码 | 分析 BaseDexClassLoader 源码 | 分析 PathDexList 源码 )
4970
Android中实现热补丁动态修复详析
1K0
【Android 热修复】热修复原理 ( 合并两个 Element[] dexElements | 自定义 Application 加载 Dex 设置 | 源码资源 )
3240
Android插件化学习之路(二)之ClassLoader完全解析
5950
【Android 安全】DEX 加密 ( 多 DEX 加载 | 65535 方法数限制和 MultiDex 配置 | PathClassLoader 类加载源码分析 | DexPathList )
9490
热修复框架HotFix源码解析
6230
Android:这是一份全面&详细的 热修复 学习指南
4410
【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 使用反射获取方法创建本应用的 dexElements | 各版本创建 dex 数组源码对比 )
2.2K0
相关推荐
手动实现Android热修复
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验