[Android]用架构师角度看插件化(2)-Replugin 唯一hook点

Replugin,为何我选择要研究这个的插件呢?很大的原因是因为它的介绍中说明,他只会有一个hook点。


一.Hook

hook点是什么?

我们入门Android的时候,一定会看到过这个图,但是你确定深刻了解到这个图的吗?


我们试着换着思维,用组件化的角度去看这张图,你会发现其层级依赖关系,与组件化的工程是非常类似的。(当然你看得角度不同,我只能说是类似)

倘若你用插件的思想来看,我们上层的众多应用(Applications)就是作为framewrok层的插件一样的存在。(Framework作为宿主一样的存在,只是它是对于应用们,他说了算,基于安全管理和效率,他能限制你们获取资源的权限和方法)

然后我们想要在独自的应用中做得像Framework层一样的加载应用,我们本身就享用了Framework层对资源等的加载机制。如果我们想要将某些资源加载,加载验证,权限限制等绕开,运用到手机本身Framework来完成,就会涉及到hook了。

以我理解:hook,当Framework运行时,拦截并替换掉Framework层中某些原生的方法或对象,让其运行到我们想要的效果。


滴滴的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点的极致了。



二.ClassLoader

对于Android 的ClassLoader,请认真仔细看下图,一张图为你解答各种疑问。

此图非常形象的说明Android里面ClassLoader的架构。


这里一般插件化框架,都是使用DexClassLoader动态加载dex文件。

DexClassLoader可以加载apk,dex,jar,还有zip后缀格式的文件,其最终应该是加载dex文件,这也是我QQ群中验证问题的答案。

BaseDexClassLoader,里面有一个DexPathList对象,是用来保存dex的列表的,而查询dex里面的资源、class都是在这个列表中遍历dex对象。

而Replugin是特别的其使用自定义的PathClassLoader来加载apk中的dex,其有别于其他插件框架。


三.唯一hook点

我们看一下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方法反射封装。


作者:Cang_Wang
链接:https://juejin.im/post/596c1fcdf265da6c436741fd
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值