DroidPlugin初探

2019-04-30  本文已影响0人  Youremywoman

第三方美小二加载直连流程

美小二插件使用的是DroidPlugin框架 所以先得理解一下这个框架的原理

DroidPlugin Git地址

参考资料


初始化插件环境

入口BizApplication onCreate方法中调用 PluginHelper.getInstance().applicationOnCreate(getBaseContext());

安装插件包

PluginManager.installPackage(String filepath, int flags) 主要功能

PackageInfo info = pm.getPackageArchiveInfo(filepath, 0); 获取插件apk包信息

PluginDirHelper.getPluginApkFile(mContext, info.packageName);安装路径data/data/{host-packagename}/Plugin/{plugin-packagename}

PluginPackageParser 利用系统的PackageParser将插件AndroidMainfest解析保存到内存中
(这里各个版本的兼容在com.morgoo.droidplugin.pm.parser包下)

启动插件包Activity

找到美小二LoadPluginActivity startPlugin 打个断点。

进入IActivityManagerHookHandle.startActivity的beforeInvoke 方法

这里面就有文章了看看开启前如何将目标Activity替换成AndroidManifest中的Activity

1. 找到startActivity方法中的intent参数
2.  IPluginManagerImpl.getActivityInfo 通过intent中的className找到插件中对应的Activity(安装插件包时有将activity信息缓存在PackageParser中),通过PackageParser的generateActivityInfo生成对应的ActivityInfo
3. 选择代理的Activity(Android有一个限制:**必须在AndroidManifest.xml中显示声明使用的Activity**),所以这里要选择一个在AndroidManifest中预先埋好的Activity
4. IPluginManagerImpl.selectStubActivityInfoByIntent 先从MyActivityManagerService的mRunningProcessList 找到是否有正在运行的进程,如果有则直接使用之,否则从mStaticProcessList中选择(mStaticProcessList中的数据在初始化插件环境的时候填充里面是宿主AndroidManifest的信息)合适的ActivityInfo(比较launchMode)。
5. 构建宿主ProxyAcitivity的intent 设置回宿主的Classloader(在插件中使用的是插件自定义classLoader要区分开)。将原来的intent当做bundle传递。

上面是将Activity替换成ProxyActivty欺骗系统的过程,下面分析AMS启动Activity时如何替换成原来的Activity.

这边在新进程第一次启动Activity重新走到宿主Application的onCreate方法。开始初始化插件进程的一些环境

  1. hook各种Binder服务。插件访问服务使用宿主的配置 (HookFactory的installHook)

  2. PluginCallbackHook的onInstall 中讲ActivityThread中的mH的mCallback替换为PluginCallback

在Activity的期待流程中可以知道AMS startActivity后会交给ActivityThread启动,ActivityThread通过

Handler mH去分发事件

  1. 在PluginCallback的handleLaunchActivity方法中打个断点.获取通过intent传递过来的原始targetIntent,获取

    我们实际要启动的ComponentName 通过插件的PackageParser获取到ActivityInfo

  2. PluginProcessManager.preLoadApk(mHostContext, targetActivityInfo);

这个方法也比较重要 做了下面几个事

  1. 我们知道Activity的创建在ActivityThread的performLaunchActivity方法中。

    activity = mInstrumentation.newActivity(
            cl, component.getClassName(), r.intent);
    

    这里的cl 被我们hook了就是.PluginClassLoader compenet是从targetIntent获取的 所以这里反射获取的是我们插件中的Activity 到这一步Activity 就替换回来了。AMS也接管了该Activity的生命周

资源问题

由于加载插件新开了个进程 第一次LoadedApk.getResources。插件中loadapk被我们hook 里面的资源resDir也是插件包路径.AssetManager的addPath也是add的resDir 所以资源是分离的。如果要宿主访问插件的资源可以使用createPackageContext方式访问

插件版本管理

我们的美小二中的插件版本管理逻辑在com.mwee.android.mwpluginupgrade.load.LoadPluginPresenter中

简单的对插件化做了下了解 还有很多问题没深入

上一篇 下一篇

猜你喜欢

热点阅读