Tencent / Shadow

零反射全动态Android插件框架
BSD 3-Clause "New" or "Revised" License
7.42k stars 1.3k forks source link

多插件处于不同进程,进行通信的问题总结 #56

Closed enzowyf closed 5 months ago

enzowyf commented 5 years ago

插件配置如下: 插件1位于plugin进程,内包含Activity和Service 插件2位于plugin_2进程,内包含Activity,并通过aidl与插件1通信

宿主,可唤起插件1和插件2中的activitym,并通过aidl与插件1通信

现象1: 直接进入插件2的Activity,通过aidl与插件1通信,正常通信,插件1的Service运行在plugin; 退出该activity,回到宿主,通过aidl与插件1通信,正常,插件1的Service运行在plugin; 再从宿主进入插件2的Activity,进入loading页后,有概率闪退回宿主,多试几次后可以成功进入

现象2: 直接进入插件2的Activity,通过aidl与插件1通信,正常通信,插件1的Service运行在plugin; 退出该activity,回到宿主,通过aidl与插件1通信,正常通信,插件1的Service运行在plugin; 反复以上操作,有概率出现在宿主通过aidl与插件1通信时,插件1的Service运行错误运行在plugin_2;

现象3: 直接进入插件1的activity,在loading页立即退出返回宿主界面,然后再进插件1的activity,有概率出现报错“PPS出现多实例”

现象4: 反复多次来回进入和退出两个插件的activity,有概率出现插件2中的activity无法启动,现象同现象1

1和4比较容易复现

enzowyf commented 5 years ago

相关问题在这个分支可以观察https://github.com/enzowyf/Shadow.git

shifujun commented 5 years ago

我先看了一下,sample-host打包的两个插件包。如下图,uuid是不一样的。 image image

uuid不一样的插件不能由同一个Loader加载起来一起工作。如果同一个进程加载了两个插件包的Loader,则会出现PPS出现多实例这样的错误。

在Shadow中也并不是uuid不一样的插件完全不能一起工作。如果两个插件进程加载不一样的uuid的插件包,有各自的Loader,如你的sample一样。两个插件互相是不需要知道对面的进程也是一个插件的,因为Service的Binder都是真的Binder。如果要这样做,可能要对sample的manager进行一些修改。我们目前提供的sample中manager没有管理多个PPS的能力,也没有假设可以同时加载不同uuid的插件。

不能同时管理多个Loader在代码上主要局限在com.tencent.shadow.dynamic.manager.PluginManagerThatUseDynamicLoader#mPluginLoader域变量只持有一个实例,那么它不是插件1的就是插件2的,应该是看先启动的谁。

shifujun commented 5 years ago

首先需要增加这个feature:支持同一个PluginManager实例管理多个插件进程 #57

enzowyf commented 5 years ago

uuid这个事情我知道,在sample-host的builde.gradle,有个自定义任务genUUID,用于统一uuid,所以应该不是uuid的问题引起的

shifujun commented 5 years ago
git fetch https://github.com/shifujun/Shadow.git issue_56
git checkout -b issue_56 FETCH_HEAD

我在你的提交基础上尝试修复了。

这里有一个设计比较隐晦,我解释一下。PluginManager有两个方向的设计,其中一个方向是怎么管理插件包,另一个方向是怎么供宿主使用。所以宿主这边拿的PluginManager实际上是com.tencent.shadow.dynamic.host.PluginManager接口来使用,实现方实现的是com.tencent.shadow.dynamic.host.PluginManagerImpl接口。而这个实现是跟插件的管理功能没有关系的。和插件管理功能有关系的是com.tencent.shadow.dynamic.manager.PluginManagerThatUseDynamicLoader,这个实现可能不应该实现com.tencent.shadow.dynamic.host.PluginManagerImpl接口,这个我们晚一些再Review一下。PluginManagerThatUseDynamicLoader的实现是持有一个插件进程的Loader去使用。

所以,我的改动,就是让SamplePluginManager不再继承PluginManagerThatUseDynamicLoader,而是直接实现PluginManagerImpl接口,然后持有两个FastPluginManager。

麻烦看一下issue提到的问题是否都解决了。我自行验证是没问题的。