资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

android热修复,Android热修复包对应哪个

Sophix及热修复原理介绍

深入探索Android热修复技术原理这本书主要讲解了Android的热修复中的热部署,冷部署以及资源和so库的修复技巧。全文主要讲Sophix应对以上四个方面的技术解析,不管是自家产品还是业界其他方案的横纵对比,Sophix技术目前都是最优的。

成都创新互联公司成立与2013年,先为余姚等服务建站,余姚等地企业,进行企业商务咨询服务。为余姚企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。

在事件分发流中,通过Hook钩子在事件传送到终点前截获并监控事件的传输,从而处理一些特定干预事件。

Sophix同时使用了热启动的底层替换方案及冷启动的类加载方案,两个方案使用的补丁是相同的。优先热启动。

基本参考InstantRun的实现:构造一个包含所有新资源的新的AssetManager。并在所有之前引用到原来的AssetManager通过反射替换掉。

Sophix不修改AssetManager的引用,构造的补丁包中只包含有新增或有修改变动的资源,在原AssetManager中addAssetPath这个包就可以了。资源包不需要在运行时合成完整包。

本质是对native方法的修复和替换。类似类修复反射注入方式,将补丁so库的路径插入到nativeLibraryDirectories数据最前面。

安卓热更难吗

热修复不难,

但热修复因为大量涉及android底层知识,又因为android本身开源,华为vivo小米几大厂商都可能修改底层相关代码,兼容性困难,所以热修复技术开发维护难度巨大,人力和时间投入不菲。目前主要有腾讯,阿里等几家互联网大厂因自身刚性需求,实现此功能。

目前热修复技术主要有以下几家:

腾讯系:

QQ超级补丁

**tinker **

阿里系:

Xposed (不支持Art虚拟机,已废弃)

Andfix (native hook兼容差,适配机型少)

Android类加载机制

Android手写热修复(一)--ClassLoader

我们平时编写的 .java 文件不是可执行文件,需要先编译成 .class 文件才可以被虚拟机执行。所谓类加载是指通过 类加载器 把class文件加载到虚拟机的内存空间,具体来说是方法区。类通常是按需加载,即第一次使用该类时才加载。

首先,Java与Android都是把类加载到虚拟机内存中,然后由虚拟机转换成设备识别的机器码。但是由于二者使用的虚拟机不同,所以在类加载方面也是有所区别的。Java的虚拟机是JVM,Android的虚拟机是dalvik/art(5.0以后虚拟机是art,是对dalvik的一种升级)。 Java虚拟机运行的是class文件,而Android 虚拟机运行的是dex文件。 dex其实是class文件的集合,是对class文件优化的产物,是为了避免出现重复的class。

从上面的讲解中,我们已经知道我们平时写的类是被 类加载器 加载尽虚拟机内存才能运行。下面就通过Framework源码来为大家讲解Android中最主要的5个类加载器。

在Activity做个简单验证:

结果:

可以看出系统类由BootClassLoader加载,apk中的类由PathClassLoader加载,PathClassLoader的父类加载器是BootClassLoader。如果暂时不能理解父类加载器是什么,没关系,后面讲双亲委托机制的时候会理解的。

下面的源码解析基于 Android SDK API28 ,这几个类加载器(除了ClassLoader)没办法直接在AS上查看源码,AS搜索到的是反编译的class的内容,是不可信的,为大家推荐一个在线工具查看, 在线查看Android Framework源码 。

用来加载本地文件系统上的文件或目录,通常是用来加载apk中我们自己写的类,而像 Activity.class 这种系统的类不是由它加载。注意:这里,并不像很多网上文章说的那样只能加载apk,本地的其他目录的文件也是可以的,这一点我会在后面验证说明。

也是被用来加载 jar 、apk、dex,通常用来加载未安装到应用中的文件。注意,它需要一个应用私有的可写的目录来存放优化后的dex文件。千万不要选择外部存储路径,因为这样可能会导致你的应用遭到注入攻击。

关于dex文件优化,可能很多人还是不理解,水平有限,我简单解释一下,

构造器参数解释:

关于optimizedDirectory:

1、这是dex优化后的路径,它必须是一个应用私有的可写的目录否则会存在注入攻击的风险;

2、这个参数在API 26(8.0)之前是有值的,之后的话,这个参数已经没有影响了,因为在调用父构造器的时候这个参数始终为null,也就是说Android 8.0 以后DexClassLoader和PathClassLoader基本一样的来;

3、在加载app的时候,apk内部的dex已经执行过优化了,优化之后放在系统目录/data/dalvik-cache下。

这个构造器的关键是初始化了一个DexPathList对象,这个是后面加载class的关键类。

这个构造方法等关键是通过 makeDexElements() 方法来获取Element数组,这个Element数组非常关键,后面查找class就会用到它,也是热修复的关键点之一。

splitDexPath(dexPath) 方法是把dexPath目录下的所有文件转换成一个File集合,如果是多个文件的话,会用 : 作为分隔符。

makeDexElements()

小结一下,这个方法就是把指定目录下的文件apk/jar/zip/dex按不同的方式封装成Element对象,然后按顺序添加到Element[]数组中。

DexPathList#loadDexFile()

可以看到 DexFile 最终是调用了openDexFile、native方法openDexFileNative去打开Dex文件的,如果outputName为空,则自动生成一个缓存目录,具体来说是 /data/dalvik-cache/xxx@classes.dex 。openDexFileNative这个native方法就不具体分析了,主要是对dex文件进行了优化操作,将优化后得odex文件通过mmap映射到内存中。感兴趣的同学可以参考:

《DexClassLoader和PathClassLoader加载Dex流程》

现在在回头看看DexClassLoader与PathClassLoader的区别。DexClassLoader可以指定odex的路径,而PathClassLoader则采用系统默认的缓存路径,在8.0以后没有区别。

ClassLoader是一个抽象类,有3个构造方法,最终调用的还是第一个构造方法,主要功能是保存实现类传入的parent参数,也就是父类加载器。ClassLoader的实现类主要有2个,一个是前面讲过的BaseDexClassLoader,另一个是BootClassLoader。

BootClassLoader是ClassLoader的内部类,而且继承了ClassLoader。

这是加载一个类的入口,流程如下:

1、 先检查这个类是否已经被加载,有的话直接返回Class对象;

2、如果没有加载过,通过父类加载器去加载,可以看出parent是通过递归的方式去加载class的;

3、如果所有的父类加载器都没有加载过,就由当前的类加载器去加载。

通常我们自己写的类是通过当前类加载器调用 findClass 方法去加载的,但是在 ClassLoader 中这是个空方法,具体的实现在它的子类 BaseDexClassLoader 中。

BaseDexClassLoader # findClass

可以看到是通过pathList去查找class的,这个对象其实之前讲过,它是在BaseDexClassLoader 的构造方法中初始化的,它实际上是一个 DexPathList 对象。

DexPathList # findClass()

对Element数组遍历,再通过Element对象的 findClass 方法去查找class,有的话就直接返回这个class,找不到则返回null。 这里可以看出获取Class是通过DexFile来实现的,而各种类加载器操作的是Dex。Android虚拟机加载的dex文件,而不是class文件。

1、加载一个类是通过双亲委托机制来实现的。

2、如果是第一次加载class,那是通过 BaseDexClassLoader 中的findClass方法实现的;接着进入 DexPathList 中的findClass方法,内部通过遍历Element数组,从Element对象中去查找类;Element实际上是对Dex文件的包装,最终还是从dexfile去查找的class。

3、一般app运行主要用到2个类加载器,一个是PathClassLoader:主要用于加载自己写的类;另一个是BootClassLoader:用于加载Framework中的类;

4、热修复和插件化一般是利用DexClassLoader来实现。

5、PathClassLoader和DexClassLoader其实都可以加载apk/jar/dex,区别是 DexClassLoader 可以指定 optimizedDirectory ,也就是 dex2oat 的产物 .odex 存放的位置,而 PathClassLoader 只能使用系统默认位置。但是在8.0 以后二者是没有区别的,只能使用系统默认的位置了。

这张图来源于:

Android虚拟机框架:类加载机制

在类加载流程分析中,我们已经知道,查找class是通过DexPathList来完成的,实际上DexPathList最终还是遍历其Element数组,获取DexFile对象来加载Class文件。 由于数组是有序的,如果2个dex文件中存在相同类名的class,那么类加载器就只会加载数组前面的dex中的class。如果apk中出现了有bug的class,那只要把修复的class打包成dex文件并且放在 DexPathList 中Element数组`的前面,就可以实现bug修复了 。下一篇为大家带来的手写热修复。

Android类加载机制的细枝末节

从JVM到Dalivk再到ART(class,dex,odex,vdex,ELF)

类加载机制系列2——深入理解Android中的类加载器

Android 热修复核心原理,ClassLoader类加载

android 插件化和热修复做什么用的

针对Android平台,Dexposed支持函数级别的在线热更新,例如对已经发布在应用市场上的宿主APK,当我们从crash统计平台上发现某个函数调用有bug,导致经常性crash,这时,可以在本地开发一个补丁APK,并发布到服务器中,宿主APK下载这个补丁APK并集成后,就可以很容易修复这个crash。

Dexposed是基于久负盛名的开源Xposed框架实现的一个Android平台上功能强大的无侵入式运行时AOP框架。

Dexposed的AOP实现是完全非侵入式的,没有使用任何注解处理器,编织器或者字节码重写器。集成Dexposed框架很简单,只需要在应用初始化阶段加载一个很小的JNI库就可以,这个加载操作已经封装在DexposedBridge函数库里面的canDexposed函数中,源码如下所示:

/**

* Check device if can run dexposed, and load libs auto.

*/

public synchronized static boolean canDexposed(Context context) {

if (!DeviceCheck.isDeviceSupport(context)) {

return false;

}

//load xposed lib for hook.

return loadDexposedLib(context);

}

private static boolean loadDexposedLib(Context context) {

// load xposed lib for hook.

try {

if (android.os.Build.VERSION.SDK_INT 19){

System.loadLibrary("dexposed_l");

} else if (android.os.Build.VERSION.SDK_INT == 10

|| android.os.Build.VERSION.SDK_INT == 9 ||

android.os.Build.VERSION.SDK_INT 14){

System.loadLibrary("dexposed");

}

return true;

} catch (Throwable e) {

return false;

}

}

Dexposed实现的hooking,不仅可以hook应用中的自定义函数,也可以hook应用中调用的Android框架的函数。Android开发者将从这一点得到很多好处,因为我们严重依赖于Android SDK的版本碎片化。

android手机厂商为什么不允许热修复

因为对手机伤害大。android手机热修复不能百分百用户修复成功,手机影响极大而且手机很容易出现bug,所以手机厂商不允许热修复。


标题名称:android热修复,Android热修复包对应哪个
文章地址:http://cdkjz.cn/article/phcjsc.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220