美文网首页
插件化之旅4-解决插件之间耦合性从loadApk开始

插件化之旅4-解决插件之间耦合性从loadApk开始

作者: Laughing_G | 来源:发表于2019-08-28 15:52 被阅读0次

    写在开头:
    上一篇插件化之旅3文章中提到了融合宿主和插件两个dex文件的方式来加载class,但是遗留了两个问题:1.多个插件同时加载导致dexElement过大,会造成内存爆棚问题;2.如果插件发生崩溃,那么同样会导致宿主崩溃,耦合性太高了。这一篇文章主要讲怎么去解决这两个问题。

    一、LoadApk是什么?

    文章开始之前,回想前面文章用到的Hook技术,通过设置接口方式将ActivityThread类的内部类Handler的handlerMessage方法捕获到,然后得到msg.obj这个对象,查看源码可知,这个obj其实是ActivityClientRecord,ActivityClientRecord是ActivityThread的静态内部类,它有一个成员对象是LoadApk。
    LoadApk是apk文件在内存中的表现形式。就跟我们以前说过的dex文件在内存中的表现形式是Element一样。

    二、源码中怎么生成LoadApk对象?

    故事的开始要从LAUNCH_ACTIVITY说起...


    image.png
    image.png

    ActivityThread这个类有个成员变量:ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<String, WeakReference<LoadedApk>>();
    这个mPackages是包名和LoadApk组合的键值对,Google工程师应该是有意而为之,给我们的插件化留了个后门。看到这里思路就产生了:将插件的包名和loadApk组合成键值对,再put到这个mPackages集合里面,这样不就形成了解耦性了吗?

    2.1问题一:如何将插件的apk转换为LoadApk对象?

    源码中可以知道,生成LoadApk对象的方法有两个,一是(public)getPackageInfoNoCheck,另一个是(private)getPackageInfo,那反射哪个方法好些呢?
    其实Google开发工程师在编写Android源代码时,有个基本的原则,就是public方法不会去修改,而private方法常常是会修改的,所以,我们反射的时候,也尽量去反射那些public的方法。
    好了,决定要反射getPackageInfoNoCheck方法,需要知道参数类型,以及调用invoke时,需要传入参数对象,getPackageInfoNoCheck里面有两个参数,类型分别是:1.ApplicationInfo;2.CompatibilityInfo。同样也是靠反射来实现:

    1.获取ApplicationInfo(就是我们在AndroidManifest.xml中注册的信息),在广播插件的文章中,我们已经反射生成了ApplicationInfo,所以现在就直接拿来使用:


    image.png

    2.获取CompatibilityInfo,得到LoadApk后要做两件事,一是替换LoadApk内部的成员变量ClassLoader;二是将插件的包名和loadApk作为键值对插入到mPackages;


    image.png

    三、为什么还要Hook PMS的getPackageInfo方法?

    前面两步我们已经能够将插件的class加入到宿主中,也能实现完美的解耦,但是只是将class加载进来了,就能启动一个Activity吗?很显然没有那么简单,Activity有自己的生命周期,她不是一个简简单单的Class类。
    接下来就要实现这样一件事,让插件的Activity,躲过系统的PMS检查,让PMS误认为插件的Activity就是宿主的Activity!
    未完待续。。。

    相关文章

      网友评论

          本文标题:插件化之旅4-解决插件之间耦合性从loadApk开始

          本文链接:https://www.haomeiwen.com/subject/jzzsectx.html