Android 插件化框架replugin replugin-host-library 源码解析

1.宿主和插件的交互

Replugin默认会使用一个常驻进程作为Server端,其他插件进程和宿主进程属于Client端。如果修改不使用常驻进程,宿主的主进程将作为插件管理进程,Server端其实就是创建了一个运行在该进程中的Provider,通过Provider的query方法返回了Binder对象来实现多进程直接的沟通和数据共享,实现插件和宿主之间沟通和数据共享,插件的安装,卸载,更新,状态判断等全部在Server端完成。

RePluginApplication 初始化 RePluginApplication.java

      super.attachBaseContext(base);
      RePluginConfig c = this.createConfig();
      if (c == null) {
          c = new RePluginConfig();
      }

      RePluginCallbacks cb = this.createCallbacks();
      if (cb != null) {
          c.setCallbacks(cb);
      }

      App.attachBaseContext(this, c);  
  }

App.attachBaseContext(this, c);

        public static void attachBaseContext(Application app, RePluginConfig config) {
            if (sAttached) {
                if (LogDebug.LOG) {
                    LogDebug.d(TAG, "attachBaseContext: Already called");
                }
                return;
            }

            RePluginInternal.init(app);
            sConfig = config;
            sConfig.initDefaults(app);

            IPC.init(app);

            // 打印当前内存占用情况
            // 只有开启“详细日志”才会输出,防止“消耗性能”
            if (LOG && RePlugin.getConfig().isPrintDetailLog()) {
                LogDebug.printMemoryStatus(LogDebug.TAG, "act=, init, flag=, Start, pn=, framework, func=, attachBaseContext, lib=, RePlugin");
            }

            // 初始化HostConfigHelper(通过反射HostConfig来实现)
            // NOTE 一定要在IPC类初始化之后才使用
            HostConfigHelper.init();

            // FIXME 此处需要优化掉
            AppVar.sAppContext = app;

            // Plugin Status Controller
            PluginStatusController.setAppContext(app);

            PMF.init(app);  //初始化application
            PMF.callAttach();

            sAttached = true;
        }

PMF.init(app);

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

        PluginManager.init(application);

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

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

        PatchClassLoaderUtils.patch(application);
    }

sPluginMgr = new PmBase(application);
PmBase.java

    void init() {

        RePlugin.getConfig().getCallbacks().initPnPluginOverride();

        if (HostConfigHelper.PERSISTENT_ENABLE) {
            // (默认)“常驻进程”作为插件管理进程,则常驻进程作为Server,其余进程作为Client
            if (IPC.isPersistentProcess()) {
                // 初始化“Server”所做工作
                initForServer();
            } else {
                // 连接到Server
                initForClient();
            }
        } else {
            // “UI进程”作为插件管理进程(唯一进程),则UI进程既可以作为Server也可以作为Client
            if (IPC.isUIProcess()) {
                // 1. 尝试初始化Server所做工作,
                initForServer();

                // 2. 注册该进程信息到“插件管理进程”中
                // 注意:这里无需再做 initForClient,因为不需要再走一次Binder
                PMF.sPluginMgr.attach();

            } else {
                // 其它进程?直接连接到Server即可
                initForClient();
            }
        }

初始化“Server”所做工作

    private final void initForServer() {
        if (LOG) {
            LogDebug.d(PLUGIN_TAG, "search plugins from file system");
        }

        mHostSvc = new PmHostSvc(mContext, this);
        PluginProcessMain.installHost(mHostSvc);
        StubProcessManager.schedulePluginProcessLoop(StubProcessManager.CHECK_STAGE1_DELAY);

        // 兼容即将废弃的p-n方案 by Jiongxuan Zhang
        mAll = new Builder.PxAll();
        Builder.builder(mContext, mAll);
        refreshPluginMap(mAll.getPlugins());

        // [Newest!] 使用全新的RePlugin APK方案
        // Added by Jiongxuan Zhang
        try {
            List<PluginInfo> l = PluginManagerProxy.load();
            if (l != null) {
                // 将"纯APK"插件信息并入总的插件信息表中,方便查询
                // 这里有可能会覆盖之前在p-n中加入的信息。本来我们就想这么干,以"纯APK"插件为准
                refreshPluginMap(l);
            }
        } catch (RemoteException e) {
            if (LOGR) {
                LogRelease.e(PLUGIN_TAG, "lst.p: " + e.getMessage(), e);
            }
        }
    }

mHostSvc = new PmHostSvc(mContext, this);

    PmHostSvc(Context context, PmBase packm) {
        mContext = context;
        mPluginMgr = packm;
        mServiceMgr = new PluginServiceServer(context);
        mManager = new PluginManagerServer(context);
    }

mServiceMgr = new PluginServiceServer(context);

PluginServiceServer负责Server端的服务调度、提供等工作,是服务的提供方,核心类之一

    // 启动插件Service。说明见PluginServiceClient的定义
    ComponentName startServiceLocked(Intent intent, Messenger client) {
        intent = cloneIntentLocked(intent);
        ComponentName cn = intent.getComponent();
//        ProcessRecord callerPr = retrieveProcessRecordLocked(client);
        final ServiceRecord sr = retrieveServiceLocked(intent);
        if (sr == null) {
            return null;
        }
        if (!installServiceIfNeededLocked(sr)) {
            return null;
        }

        sr.startRequested = true;

        // 加入到列表中,统一管理
        mServicesByName.put(cn, sr);

        if (LOG) {
            LogDebug.i(PLUGIN_TAG, "PSM.startService(): Start! in=" + intent + "; sr=" + sr);
        }

        // 从binder线程post到ui线程,去执行Service的onStartCommand操作
        Message message = mHandler.obtainMessage(WHAT_ON_START_COMMAND);
        Bundle data = new Bundle();
        data.putParcelable("intent", intent);
        message.setData(data);
        message.obj = sr;
        mHandler.sendMessage(message);

        return cn;
    }

    // 停止插件的Service。说明见PluginServiceClient的定义
    int stopServiceLocked(Intent intent) {
        intent = cloneIntentLocked(intent);
        ServiceRecord sr = getServiceLocked(intent);
        if (sr == null) {
            return 0;
        }
        sr.startRequested = false;
        recycleServiceIfNeededLocked(sr);

        if (LOG) {
            LogDebug.i(PLUGIN_TAG, "PSM.stopService(): Stop! in=" + intent + "; sr=" + sr);
        }
        return 1;
    }

mManager = new PluginManagerServer(context);
PluginManagerServer插件管理器,控制插件的安装、卸载、获取等,运行在常驻进程中

initForClient 连接到Server


    /**
     * Client(UI进程)的初始化
     *
     */
    private final void initForClient() {
        if (LOG) {
            LogDebug.d(PLUGIN_TAG, "list plugins from persistent process");
        }

        // 1. 先尝试连接
        PluginProcessMain.connectToHostSvc();

        // 2. 然后从常驻进程获取插件列表
        refreshPluginsFromHostSvc();
    }

2.插件的安装

RePlugin.java

    /**
     * 安装或升级此插件 <p>
     * 注意: <p>
     * 1、这里只将APK移动(或复制)到“插件路径”下,不释放优化后的Dex和Native库,不会加载插件 <p>
     * 2、支持“纯APK”和“p-n”(旧版,即将废弃)插件 <p>
     * 3、此方法是【同步】的,耗时较少 <p>
     * 4、不会触发插件“启动”逻辑,因此只要插件“当前没有被使用”,再次调用此方法则新插件立即生效
     *
     * @param path 插件安装的地址。必须是“绝对路径”。通常可以用context.getFilesDir()来做
     * @return 安装成功的插件信息,外界可直接读取
     * @since 2.0.0 (1.x版本为installDelayed)
     */
    public static PluginInfo install(String path) {
        if (TextUtils.isEmpty(path)) {
            throw new IllegalArgumentException();
        }

        // 判断文件合法性
        File file = new File(path);
        if (!file.exists()) {
            if (LogDebug.LOG) {
                LogDebug.e(TAG, "install: File not exists. path=" + path);
            }
            return null;
        } else if (!file.isFile()) {
            if (LogDebug.LOG) {
                LogDebug.e(TAG, "install: Not a valid file. path=" + path);
            }
            return null;
        }

        // 若为p-n开头的插件,则必须是从宿主设置的“插件安装路径”上(默认为files目录)才能安装,其余均不允许
        if (path.startsWith("p-n-")) {
            String installPath = RePlugin.getConfig().getPnInstallDir().getAbsolutePath();
            if (!path.startsWith(installPath)) {
                if (LogDebug.LOG) {
                    LogDebug.e(TAG, "install: Must be installed from the specified path. Path=" + path + "; Allowed=" + installPath);
                }
                return null;
            }
        }

        return MP.pluginDownloaded(path);
    }

MP.pluginDownloaded(path)

    public static final PluginInfo pluginDownloaded(String path) {
        if (LOG) {
            LogDebug.d(PLUGIN_TAG, "MP.pluginDownloaded ... path=" + path);
        }

        /**
         * 问题描述:
         *
         * 对于正在生效的插件,如果当前时机pluginHost没有存活,那么这里会先启动pluginHost,然后再调用它的PluginHost进程的pluginDownloaded接口
         *
         * 这里的问题是:pluginHost进程在启动过程会通过扫描文件的方式将当前即将生效的插件识别到,
         * 而在进程ready后,再去调用pluginDownloaded接口的时候会认为它不是新插件,从而不会通过NEW_PLUGIN广播来周知所有进程新插件生效了
         * 因此,当前进程也不会同步新插件生效的逻辑。
         * so,问题就来了,当前进程新下载的插件由于pluginHost的逻辑无法正常生效。
         * 当然该问题只针对p-n格式的插件,而纯APK格式的插件不再使用进程启动的时候通过扫描文件目录的方式来来识别所有准备好的插件
         *
         * 解决办法:
         * 对于处于该流程的插件文件(p-n插件)加上lock文件,以表示当前插件正在生效,不需要plugHost进程再次扫描生效了,也就不存在新插件在新进程中成为了老插件
         */

        ProcessLocker lock = null;

        try {
            if (path != null) {
                File f = new File(path);
                String fileName = f.getName();
                String fileDir = f.getParent();
                if (fileName.startsWith("p-n-")) {
                    lock = new ProcessLocker(RePluginInternal.getAppContext(), fileDir, fileName + ".lock");
                }
            }

            if (lock != null && !lock.tryLock()) {
                // 加锁
                if (LOG) {
                    LogDebug.d(PLUGIN_TAG, "MP.pluginDownloaded ... lock file + " + path + " failed! ");
                }
            }

            PluginInfo info = PluginProcessMain.getPluginHost().pluginDownloaded(path);
            if (info != null) {
                RePlugin.getConfig().getEventCallbacks().onInstallPluginSucceed(info);
            }
            return info;
        } catch (Throwable e) {
            if (LOGR) {
                LogRelease.e(PLUGIN_TAG, "mp.pded: " + e.getMessage(), e);
            }
        } finally {
            // 去锁
            if (lock != null) {
                lock.unlock();
            }
        }
        return null;
    }

PmHostSvc.java

    @Override
    public PluginInfo pluginDownloaded(String path) throws RemoteException {
        if (LOG) {
            LogDebug.d(PLUGIN_TAG, "pluginDownloaded: path=" + path);
        }

        // 通过路径来判断是采用新方案,还是旧的P-N(即将废弃,有多种)方案
        PluginInfo pi;
        String fn = new File(path).getName();
        if (fn.startsWith("p-n-") || fn.startsWith("v-plugin-") || fn.startsWith("plugin-s-") || fn.startsWith("p-m-")) {
            pi = pluginDownloadedForPn(path);
        } else {
            pi = mManager.getService().install(path);
        }

        if (pi != null) {
            // 通常到这里,表示“安装已成功”,这时不管处于什么状态,都应该通知外界更新插件内存表
            syncInstalledPluginInfo2All(pi);

        }
        return pi;
    }

PluginManagerServer.java

   private PluginInfo installLocked(String path) {
        final boolean verifySignEnable = RePlugin.getConfig().getVerifySign();
        final int flags = verifySignEnable ? PackageManager.GET_META_DATA | PackageManager.GET_SIGNATURES : PackageManager.GET_META_DATA;

        // 1. 读取APK内容
        PackageInfo pi = mContext.getPackageManager().getPackageArchiveInfo(path, flags);
        if (pi == null) {
            if (LogDebug.LOG) {
                LogDebug.e(TAG, "installLocked: Not a valid apk. path=" + path);
            }

            RePlugin.getConfig().getEventCallbacks().onInstallPluginFailed(path, RePluginEventCallbacks.InstallResult.READ_PKG_INFO_FAIL);
            return null;
        }

        // 2. 校验插件签名
        if (verifySignEnable) {
            if (!verifySignature(pi, path)) {
                return null;
            }
        }

        // 3. 解析出名字和三元组
        PluginInfo instPli = PluginInfo.parseFromPackageInfo(pi, path);
        if (LogDebug.LOG) {
            LogDebug.i(TAG, "installLocked: Info=" + instPli);
        }
        instPli.setType(PluginInfo.TYPE_NOT_INSTALL);

        // 若要安装的插件版本小于或等于当前版本,则安装失败
        // NOTE 绝大多数情况下,应该在调用RePlugin.install方法前,根据云端回传的信息来判断,以防止下载旧插件,浪费流量
        // NOTE 这里仅做双保险,或通过特殊渠道安装时会有用

        // 注意:这里必须用“非Clone过的”PluginInfo,因为要修改里面的内容
        PluginInfo curPli = MP.getPlugin(instPli.getName(), false);
        if (curPli != null) {
            if (LogDebug.LOG) {
                LogDebug.i(TAG, "installLocked: Has installed plugin. current=" + curPli);
            }

            // 版本较老?直接返回
            final int checkResult = checkVersion(instPli, curPli);
            if (checkResult < 0) {
                RePlugin.getConfig().getEventCallbacks().onInstallPluginFailed(path, RePluginEventCallbacks.InstallResult.VERIFY_VER_FAIL);
                return null;
            } else if (checkResult == 0){
                instPli.setIsPendingCover(true);
            }
        }

        // 4. 将合法的APK改名后,移动(或复制,见RePluginConfig.isMoveFileWhenInstalling)到新位置
        // 注意:不能和p-n的最终释放位置相同,因为管理方式不一样
        if (!copyOrMoveApk(path, instPli)) {
            RePlugin.getConfig().getEventCallbacks().onInstallPluginFailed(path, RePluginEventCallbacks.InstallResult.COPY_APK_FAIL);
            return null;
        }

        // 5. 从插件中释放 So 文件
        PluginNativeLibsHelper.install(instPli.getPath(), instPli.getNativeLibsDir());

        // 6. 若已经安装旧版本插件,则尝试更新插件信息,否则直接加入到列表中
        if (curPli != null) {
            updateOrLater(curPli, instPli);
        } else {
            mList.add(instPli);
        }

        // 7. 保存插件信息到文件中,下次可直接使用
        mList.save(mContext);

        return instPli;
    }

3.插件的加载

RePlugin.java

        public static void attachBaseContext(Application app, RePluginConfig config) {
            if (sAttached) {
                if (LogDebug.LOG) {
                    LogDebug.d(TAG, "attachBaseContext: Already called");
                }
                return;
            }

            RePluginInternal.init(app);
            sConfig = config;
            sConfig.initDefaults(app);

            IPC.init(app);

            // 打印当前内存占用情况
            // 只有开启“详细日志”才会输出,防止“消耗性能”
            if (LOG && RePlugin.getConfig().isPrintDetailLog()) {
                LogDebug.printMemoryStatus(LogDebug.TAG, "act=, init, flag=, Start, pn=, framework, func=, attachBaseContext, lib=, RePlugin");
            }

            // 初始化HostConfigHelper(通过反射HostConfig来实现)
            // NOTE 一定要在IPC类初始化之后才使用
            HostConfigHelper.init();

            // FIXME 此处需要优化掉
            AppVar.sAppContext = app;

            // Plugin Status Controller
            PluginStatusController.setAppContext(app);

            PMF.init(app);
            PMF.callAttach();

            sAttached = true;
        }


PMF.callAttach();


    public static final void callAttach() {
        sPluginMgr.callAttach();
    }

    final void callAttach() {
        //
        mClassLoader = PmBase.class.getClassLoader();

        // 挂载
        for (Plugin p : mPlugins.values()) {
            p.attach(mContext, mClassLoader, mLocal);
        }

        // 加载默认插件
        if (PluginManager.isPluginProcess()) {
            if (!TextUtils.isEmpty(mDefaultPluginName)) {
                //
                Plugin p = mPlugins.get(mDefaultPluginName);
                if (p != null) {
                    boolean rc = p.load(Plugin.LOAD_APP, true);
                    if (!rc) {
                        if (LOG) {
                            LogDebug.d(PLUGIN_TAG, "failed to load default plugin=" + mDefaultPluginName);
                        }
                    }
                    if (rc) {
                        mDefaultPlugin = p;
                        mClient.init(p);
                    }
                }
            }
        }
    }

boolean rc = p.load(Plugin.LOAD_APP, true);

    final boolean load(int load, boolean useCache) {
        PluginInfo info = mInfo;
        boolean rc = loadLocked(load, useCache);
        // 尝试在此处调用Application.onCreate方法
        // Added by Jiongxuan Zhang
        if (load == LOAD_APP && rc) {
            callApp();
        }
        // 如果info改了,通知一下常驻
        // 只针对P-n的Type转化来处理,一定要通知,这样Framework_Version也会得到更新
        if (rc && mInfo != info) {
            UpdateInfoTask task = new UpdateInfoTask((PluginInfo) mInfo.clone());
            Tasks.post2Thread(task);
        }
        return rc;
    }

4.启动插件的Activity

RePlugin.java

    public static boolean startActivity(Context context, Intent intent) {
        // TODO 先用旧的开启Activity方案,以后再优化
        ComponentName cn = intent.getComponent();
        if (cn == null) {
            // TODO 需要支持Action方案
            return false;
        }
        String plugin = cn.getPackageName();
        String cls = cn.getClassName();
        return Factory.startActivityWithNoInjectCN(context, intent, plugin, cls, IPluginManager.PROCESS_AUTO);
    }

PluginLibraryInternalProxy.java




 public boolean startActivity(Context context, Intent intent, String plugin, String activity, int process, boolean download)


        ComponentName cn = mPluginMgr.mLocal.loadPluginActivity(intent, plugin, activity, process);
        if (cn == null) {
            if (LOG) {
                LogDebug.d(PLUGIN_TAG, "plugin cn not found: intent=" + intent + " plugin=" + plugin + " activity=" + activity + " process=" + process);
            }
            return false;
        }

public ComponentName loadPluginActivity(Intent intent, String plugin, String activity, int process) {

        ActivityInfo ai = null;
        String container = null;
        PluginBinderInfo info = new PluginBinderInfo(PluginBinderInfo.ACTIVITY_REQUEST);

        try {
            // 获取 ActivityInfo(可能是其它插件的 Activity,所以这里使用 pair 将 pluginName 也返回)
            ai = getActivityInfo(plugin, activity, intent);
            if (ai == null) {
                if (LOG) {
                    LogDebug.d(PLUGIN_TAG, "PACM: bindActivity: activity not found");
                }
                return null;
            }

            // 存储此 Activity 在插件 Manifest 中声明主题到 Intent
            intent.putExtra(INTENT_KEY_THEME_ID, ai.theme);
            if (LOG) {
                LogDebug.d("theme", String.format("intent.putExtra(%s, %s);", ai.name, ai.theme));
            }

            // 根据 activity 的 processName,选择进程 ID 标识
            if (ai.processName != null) {
                process = PluginClientHelper.getProcessInt(ai.processName);
            }

            // 容器选择(启动目标进程)
            IPluginClient client = MP.startPluginProcess(plugin, process, info);
            if (client == null) {
                return null;
            }
            // 远程分配坑位
            container = client.allocActivityContainer(plugin, process, ai.name, intent);
            ......
}

IPluginClient client = MP.startPluginProcess(plugin, process, info);


    public static final IPluginClient startPluginProcess(String plugin, int process, PluginBinderInfo info) throws RemoteException {
        return PluginProcessMain.getPluginHost().startPluginProcess(plugin, process, info);
    }

    /**
     * sPluginHostLocal 常驻进程使用,非常驻进程为null buyuntao
     * sPluginHostRemote 非常驻进程使用,常驻进程为null,用于非常驻进程连接常驻进程  buyuntao
     * @hide 内部框架使用
     */
    public static final IPluginHost getPluginHost() {
        if (sPluginHostLocal != null) {
            return sPluginHostLocal;
        }
        // 可能是第一次,或者常驻进程退出了
        if (sPluginHostRemote == null) {
            if (LogDebug.LOG) {
                if (IPC.isPersistentProcess()) {
                    LogDebug.e(PLUGIN_TAG, "插件框架未正常初始化");
                    throw new RuntimeException("插件框架未正常初始化");
                }
            }
            // 再次唤起常驻进程
            connectToHostSvc();
        }
        return sPluginHostRemote;
    }
class PmHostSvc extends IPluginHost.Stub {

	    @Override
    public IPluginClient startPluginProcess(String plugin, int process, PluginBinderInfo info) throws RemoteException {
        return mPluginMgr.startPluginProcessLocked(plugin, process, info);
    }
	
	...
	
}

class PluginProcessPer extends IPluginClient.Stub {

    public String allocActivityContainer(String plugin, int process, String target, Intent intent) throws RemoteException {
        // 一旦有分配,则进入监控状态(一是避免不退出的情况,二也是最重要的是避免现在就退出的情况)
        RePlugin.getConfig().getEventCallbacks().onPrepareAllocPitActivity(intent);

        String loadPlugin = null;
        // 如果UI进程启用,尝试使用传过来的插件,强制用UI进程
        if (Constant.ENABLE_PLUGIN_ACTIVITY_AND_BINDER_RUN_IN_MAIN_UI_PROCESS) {
            if (IPC.isUIProcess()) {
                loadPlugin = plugin;
                process = IPluginManager.PROCESS_UI;
            } else {
                loadPlugin = plugin;
            }
        }
        // 如果不成,则再次尝试使用默认插件
        if (TextUtils.isEmpty(loadPlugin)) {
            if (mDefaultPlugin == null) {
                if (LOGR) {
                    LogRelease.e(PLUGIN_TAG, "a.a.c p i n");
                }
                return null;
            }
            loadPlugin = mDefaultPlugin.mInfo.getName();
        }
        //
        String container = bindActivity(loadPlugin, process, target, intent);
        if (LOG) {
            LogDebug.d(PLUGIN_TAG, "PACM: eval plugin " + loadPlugin + ", target=" + target + ", container=" + container);
        }
        return container;
    }

	...
}

5.Replugin Hook系统ClassLoader

application初始化 PMF.java



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

        PluginManager.init(application);

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

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

        PatchClassLoaderUtils.patch(application);
    }

PatchClassLoaderUtils.patch(application);

/**
 * 对宿主的HostClassLoader做修改。这是RePlugin中唯一需要修改宿主私有属性的位置了
 *
 * @author RePlugin Team
 */
public class PatchClassLoaderUtils {

    private static final String TAG = "PatchClassLoaderUtils";

    public static boolean patch(Application application) {
        try {
            // 获取Application的BaseContext (来自ContextWrapper)
            Context oBase = application.getBaseContext();
            if (oBase == null) {
                if (LOGR) {
                    LogRelease.e(PLUGIN_TAG, "pclu.p: nf mb. ap cl=" + application.getClass());
                }
                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) {
                if (LOGR) {
                    LogRelease.e(PLUGIN_TAG, "pclu.p: nf mpi. mb cl=" + oBase.getClass());
                }
                return false;
            }

            // mPackageInfo的类型主要有两种:
            // 1. android.app.ActivityThread$PackageInfo - Android 2.1 - 2.3
            // 2. android.app.LoadedApk - Android 2.3.3 and higher
            if (LOG) {
                Log.d(TAG, "patch: mBase cl=" + oBase.getClass() + "; mPackageInfo cl=" + oPackageInfo.getClass());
            }

            // 获取mPackageInfo.mClassLoader
            ClassLoader oClassLoader = (ClassLoader) ReflectUtils.readField(oPackageInfo, "mClassLoader");
            if (oClassLoader == null) {
                if (LOGR) {
                    LogRelease.e(PLUGIN_TAG, "pclu.p: nf mpi. mb cl=" + oBase.getClass() + "; mpi cl=" + oPackageInfo.getClass());
                }
                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);

            if (LOG) {
                Log.d(TAG, "patch: patch mClassLoader ok");
            }
        } catch (Throwable e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

ClassLoader cl = RePlugin.getConfig().getCallbacks().createClassLoader(oClassLoader.getParent(), oClassLoader);

    public RePluginClassLoader createClassLoader(ClassLoader parent, ClassLoader original) {
        return new RePluginClassLoader(parent, original);
    }

Replugin的ClassLoader

在Replugin中有两个ClassLoader,一个加载宿主RePluginClassLoader,一个加载插件apk类的PluginDexClassLoader

RePluginClassLoader.java


    @Override
    protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
        //
        Class<?> c = null;
        c = PMF.loadClass(className, resolve);
        if (c != null) {
            return c;
        }
        //
        try {
            c = mOrig.loadClass(className);
            // 只有开启“详细日志”才会输出,防止“刷屏”现象
            if (LogDebug.LOG && RePlugin.getConfig().isPrintDetailLog()) {
                LogDebug.d(TAG, "loadClass: load other class, cn=" + className);
            }
            return c;
        } catch (Throwable e) {
            //
        }
        //
        return super.loadClass(className, resolve);
    }

PluginDexClassLoader.java

    @Override
    protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
        // 插件自己的Class。从自己开始一直到BootClassLoader,采用正常的双亲委派模型流程,读到了就直接返回
        Class<?> pc = null;
        ClassNotFoundException cnfException = null;
        try {
            pc = super.loadClass(className, resolve);
            if (pc != null) {
                // 只有开启“详细日志”才会输出,防止“刷屏”现象
                if (LogDebug.LOG && RePlugin.getConfig().isPrintDetailLog()) {
                    LogDebug.d(TAG, "loadClass: load plugin class, cn=" + className);
                }
                return pc;
            }
        } catch (ClassNotFoundException e) {
            // Do not throw "e" now
            cnfException = e;

            if (PluginDexClassLoaderPatch.need2LoadFromHost(className)) {
                try {
                    return loadClassFromHost(className, resolve);
                } catch (ClassNotFoundException e1) {
                    // Do not throw "e1" now
                    cnfException = e1;

                    if (LogDebug.LOG) {
                        LogDebug.e(TAG, "loadClass ClassNotFoundException, from HostClassLoader&&PluginClassLoader, cn=" + className + ", pluginName=" + mPluginName);
                    }
                }
            } else {
                if (LogDebug.LOG) {
                    LogDebug.e(TAG, "loadClass ClassNotFoundException, from PluginClassLoader, cn=" + className + ", pluginName=" + mPluginName);
                }
            }
        }

        // 若插件里没有此类,则会从宿主ClassLoader中找,找到了则直接返回
        // 注意:需要读取isUseHostClassIfNotFound开关。默认为关闭的。可参见该开关的说明
        if (RePlugin.getConfig().isUseHostClassIfNotFound()) {
            try {
                return loadClassFromHost(className, resolve);
            } catch (ClassNotFoundException e) {
                // Do not throw "e" now
                cnfException = e;
            }
        }

        // At this point we can throw the previous exception
        if (cnfException != null) {
            throw cnfException;
        }
        return null;
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值