你们好,我系苍王。
java
如下是我这个系列的相关文章,有兴趣能够参考一下,能够给个喜欢或者关注个人文章。安全
Replugin,为什么我选择要研究这个的插件呢?很大的缘由是由于它的介绍中说明,他只会有一个hook点。app
hook点是什么?框架
咱们入门Android的时候,必定会看到过这个图,可是你肯定深入了解到这个图的吗?组件化
咱们试着换着思惟,用组件化的角度去看这张图,你会发现其层级依赖关系,与组件化的工程是很是相似的。(固然你看得角度不一样,我只能说是相似)学习
假若你用插件的思想来看,咱们上层的众多应用(Applications)就是做为framewrok层的插件同样的存在。(Framework做为宿主同样的存在,只是它是对于应用们,他说了算,基于安全管理和效率,他能限制大家获取资源的权限和方法)插件
而后咱们想要在独自的应用中作得像Framework层同样的加载应用,咱们自己就享用了Framework层对资源等的加载机制。若是咱们想要将某些资源加载,加载验证,权限限制等绕开,运用到手机自己Framework来完成,就会涉及到hook了。3d
以我理解:hook,当Framework运行时,拦截并替换掉Framework层中某些原生的方法或对象,让其运行到咱们想要的效果。cdn
滴滴的VirtualApk 会hook掉AMS(ActivityManagerService)和Instumentation,这两个Framework的文件很是重要,AMS是四大组件的入口,管理生命周期,管理应用通讯等,Instumentation管理了Activity的生命周期的调用。有兴趣能够深刻去看这两个Framework文件。而其余旧式插件化,还会hook掉一下Service,Broadcast的机制。
而Replugin却走的是彻底和传统插件化不一样的路,它hook掉的是ClassLoader,并且它只有惟一的hook点。
hook为什么会不安全?
就是拦截和替换原生机制,由于Android的机型太多了,并且是开源的,那么各个厂商定制Rom的修改,不一样版本的适配也是很是大的阻碍,假若替换掉某些厂商修改Google原生Android的源码里面的方案,2️⃣恰好hook点没有兼容这方面的源码,就有引发hook失败或者崩溃的可能性。
意味着hook点越少,其可能产生修改的代码会变小,维护的代价会变小,耗损的人力资源就会变少,整个用户体验就会提高。
架构的标准,是要懂得,衡量 时间+空间+效率。惟一hook点,暂时Replugin应该是插件化hook点的极致了。
对于Android 的ClassLoader,请认真仔细看下图,一张图为你解答各类疑问。
此图很是形象的说明Android里面ClassLoader的架构。
这里通常插件化框架,都是使用DexClassLoader动态加载dex文件。
DexClassLoader能够加载apk,dex,jar,还有zip后缀格式的文件,其最终应该是加载dex文件,这也是我QQ群中验证问题的答案。
BaseDexClassLoader,里面有一个DexPathList对象,是用来保存dex的列表的,而查询dex里面的资源、class都是在这个列表中遍历dex对象。
而Replugin是特别的其使用自定义的PathClassLoader来加载apk中的dex,其有别于其余插件框架。
咱们看一下Replugin的加载过程。
用的是官网的replugin-host-library为例子
Application中attachBaseContext是最快执行的,其调用了Replugin.App.attachBaseContext方法
他会调用到PMF这个类init方法,PMF是框架和住程序接口
其里面会调用pluginManger的初始化,还有PatchClassLoaderUtils.patch的方法。
PatchClassLoaderUitls这个类是修改宿主和私有属性的位置,其实就是那个惟一的hook点的位置
能够看到在patch中须要获取到整个application的context对象。
而后生成本身的classLoader对象,去hook掉mClassLoader对象,FieldUtils是对Java反射机制的封装,之后使用到发射的时候,能够参考一下这里的封装,感受是迄今看到众多插件化的封装最完善的。
这里的对参数的说明很清晰,最终会返回RePluginClassLoader对象。
这里调用到RepluginClassLoader里面,copyFromOrginal会将一些须要更改的属性去掉final属性,才能开始修改。initMethods,反射来替换掉ClassLoader的方法
里面替换掉四个方法,findResource和findResources是资源的获取,findLibrary是库获取,getPackage就是获取包信息了。
这里MethodUtils是方法反射的封装,也是封装得很是好。
在Android源码中,是经过DexPathList中读取资源,Resource是以URL格式返回,而lib库是用String返回
包获取是在classLoader中完成的
这里你会发现有点矛盾的地方,由于有可能不是那么容易一会儿能看明。
咱们前面看到须要反射出一些BaseDexLoader的一些方法
可是你看到其继承调用的时候,却使用了如出一辙的方法,这样不就用了如出一辙的流程了?这有何意义?
这里其实意义就在于其传入的mOrig参数,这个参数是classLoader的对象,而不一样插件间都有classloader,那么其分别调用插件间的classloader资源的时候,就须要在这里拦截调用。
以上就是对Replugin的惟一hook点的分析。
值得借鉴的地方。
(1)惟一hook点,是用hook掉足够大的ClassLoader对象,来让资源加载获得更加便利。
(2)Java反射机制的整合FieldUtils域反射封装和MethodUtils方法反射封装。
这里发一条广告,我创立了一个小密圈。
天天会分享java基础,组件化插件化相关,音视频开源项目分享。在管理员们的努力下,提供了动脑学院vip,慕课网的Android付费资源。
最重要,带有群员们珍贵的分析和点评。
还有最新插件化框架的分析和运用,组件化架构技巧的分享,都尽在这里。
不须要一顿饭的价钱 ,68/一全年的学习资料。
付费是真干货,真正节省时间的通往技术的途径。
来到这里但愿影响你的不仅是技术提高,并且是人生的架构的导向。
成立两周已经有超过190+的小伙伴加入了咱们的行列了,而且持续增长,让咱们一块儿成长,群内还有不定时福利,包括原创书籍的福利哦。
我创建了一个关于Android架构学习的群,里面能够进一步进行组件化学习的交流。
群号是316556016,也能够扫码进群。我在这里期待大家的加入!!!