Android 插件化框架 Replugin 源码解读(二)hook系统ClassLoader

        在上一章节中我们讲到了Replugin初始化的时候创建了插件管理进程作为服务端。其他工作进程作为客户端,然后分别在各自的进程中初始化自己要做的事情。创建了多个Binder对象用来完成客户端和服务端的信息交互。在完成PmBase 的初始化后。在PMF.init()中还有剩下的部分代码

com.qihoo360.loader2.PMF


 public static final void init(Application application) {
        setApplicationContext(application);

        PluginManager.init(application);

        sPluginMgr = new PmBase(application);
        sPluginMgr.init();

        Factory.sPluginManager = PMF.getLocal();//1
        Factory2.sPLProxy = PMF.getInternal();//2

        PatchClassLoaderUtils.patch(application);//3
    }

"1"中PMF.getLocal()就是在PmBase 构造函数中 创建的PluginCommImpl。这个类负责宿主与插件、插件间的互通,因此这个类中的方法使用的频率会比较高。而Factory类是一个包装类,缓存了PluginCommImpl对象,方便以后的调用。同样的"2"中的PMF.getInternal() 就是在PmBase 中创建的PluginLibraryInternalProxy。同样的这个类中的方法也会经常使用到,比如说startActivity这个方法。

"3"PatchClassLoaderUtils.patch(application)这里的逻辑就涉及到这个框架的核心唯一hook 的点,hook系统的ClassLoader

Replugin唯一hook点 hook系统ClassLoader

Replugin是如何hook 系统的ClassLoader。

//com.qihoo360.loader.utils.PatchClassLoaderUtils

public class PatchClassLoaderUtils {

    

    public static boolean patch(Application application) {
        try {
            // 获取Application的BaseContext (来自ContextWrapper)
            Context oBase = application.getBaseContext();
            if (oBase == null) {
                
                return false;
            }

            // 获取mBase.mPackageInfo
            // 1. ApplicationContext - Android 2.1
            // 2. ContextImpl - Android 2.2 and higher
            // 3. AppContextImpl - Android 2.2 and higher
            Object oPackageInfo = ReflectUtils.readField(oBase, "mPackageInfo");
           
            if (oPackageInfo == null) {
                
                return false;
            }

            // mPackageInfo的类型主要有两种:
            // 1. android.app.ActivityThread$PackageInfo - Android 2.1 - 2.3
            // 2. android.app.LoadedApk - Android 2.3.3 and higher
            

            // 获取mPackageInfo.mClassLoader
            ClassLoader oClassLoader = (ClassLoader) ReflectUtils.readField(oPackageInfo, "mClassLoader");
            if (oClassLoader == null) {
              
                return false;
            }

            // 外界可自定义ClassLoader的实现,但一定要基于RePluginClassLoader类
            ClassLoader cl = RePlugin.getConfig().getCallbacks().createClassLoader(oClassLoader.getParent(), oClassLoader);

            // 将新的ClassLoader写入mPackageInfo.mClassLoader
            ReflectUtils.writeField(oPackageInfo, "mClassLoader", cl);

            // 设置线程上下文中的ClassLoader为RePluginClassLoader
            // 防止在个别Java库用到了Thread.currentThread().getContextClassLoader()时,“用了原来的PathClassLoader”,或为空指针
            Thread.currentThread().setContextClassLoader(cl);

            
        } catch (Throwable e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

  这里利用了反射工具,是代码看上去非常简洁。主要做了这么几件事情

1. application.getBaseContext() 获取APP的BaseContext

2.利用反射获取BaseContext 中的mPackageInfo字段,他的类型是LoadedApk类型 

3.利用反射获取mPackageInfo 中的mClassLoader字段。

4.通过宿主的父ClassLoader和宿主ClassLoader利用RePluginCallbacks的createClassLoader方法生成RePluginClassLoader

5.替换mPackageInf

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值