[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?

大家好,我系苍王。

以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章。

[Android]如何做一个崩溃率少于千分之三噶应用app--章节列表


一.占坑

什么是占坑?为什么要占坑?

Android插件化中,从一个插件Activity跳转到不同插件的Activity的时候,是否可以能正常跳转成功?

声明Activity需要配置什么?

声明Activity是需要AndroidManifest中声明,但是插件是依赖于宿主的,插件声明了Activity,但是插件的AndroidManifest信息,是无法动态配置到宿主里面的。

那AndroidManifest在什么时候注入的?其实这个是在App安装的时候,PackageManagerService就会读取到AndroidManifest里面的配置信息并保存一份到PackageManagerService.Settings当中,那么基本无法动态的改变这份配置信息。如果以后能动态的改变Android中记录的App配置信息,那么我们就不需要占坑了。

正因为一开始就已经将配置AndroidManifest记录到PackageManagerService,里面的记录的Activity的信息,将也会保存到PackageManagerService中。我们使用startActivity的时候,ActivityManagerService将会Activity的合法信息传送到Native层作配置验证,如果无法找到跳转Activity的配置,那么将抛出异常。

插件是app运行时,动态将插件信息插入classLoader的dex列表当中。但是宿主的AndroidManifest配置是无法动态去配置修改的。那么插件中的跳转,如何越过这种困境呢?

工程师聪明的,他们提前在宿主声明一些空Activity信息到AndoridManifest当中,然后在使用startActivity后在ActivityManagerService中在跳转到Native层前将替换成员AndroidManifest的空Activity,欺骗验证,然后Native层验证过后,在传回ActivityManagerService层后替换回需要跳转的Activity的信息。这种声明空Activity信息到AndroidManifest的行为,我们就叫做占坑了。

结合上一节,hook点来看,占坑替换是需要hook掉ActivityManagerService来完成这样的操作的,但是上一节已经介绍过Replugin唯一hook点在classloader了,那么这个占坑替换又是如何完成呢?


二.Replugin 占坑处理

宿主在引入gradle-host-library的时候,就已经引入了Replugin的占坑操作了。

Replugin在库中的AndroidManifest,已经提前的声明了各种各样的Activity Service Proivder,然后BroadcastReceiver可以动态注册,所以并不需要占坑。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第1张图片

我们可以看到${applicationId}它将会直接引用到宿主app build.gradle中的applicationId完成。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第2张图片

我们可以看到这些坑位会被合并到在宿主的full的AndroidManifest.xml里面。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第3张图片

你拖到最后,会发现除了这些坑位外,还会有很多360的坑位添加了,这是如何做到的呢?

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第4张图片

这里关键在于引用了replugin-host-gradle中的配置,我们在ComponentsGenerator.groovy文件,会使用Gradle命令编译时生成这些占坑声明。之后深入介绍replugin的gradle文件的时候,会给大家更加深入介绍。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第5张图片

二.Replugin 跳转流程

我们看一下使用Replugin封装的的跳转

很清晰的看到pluginName,相当于Android的包名来填写。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第6张图片

startActivity的时候,从intent中获取包名和类名,然后再调用Factory.startActivityWithNoInjectCN

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第7张图片

然后继续使用插件管理的继续跳转函数

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第8张图片

这里IPluginManager对参数等说明非常情况,说明是公司的技术追求还是很高的。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第9张图片

进入到底层的PmLocalImpl中

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第10张图片

然后更深入添加参数

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第11张图片

在PmInternalImpl终于可以看真正实现,这里先要判断是否插件已经下载,getPluginConfigInfo会获取是否存在手机中是否存在插件。

然后isNeedToDownLoad来启动下载。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第12张图片

这里就是一些基础的下载封装了。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第13张图片

下载时需要上锁处理,表示当前插件正在生效。ProcessLocker是自定义的进程锁。

PluginProcressMain.getPluginHost().pluginDownloaded将会下载并加载插件,我们留到下一节再介绍,这个过程。

tryLock和unlock的调用就是对进程的锁定了。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第14张图片

ProcessLock里面,是使用文件锁来完成上锁的,这里的进程锁,正确的来说是文件锁。

这里面创建出文件后缀为.lock的文件,作为文件锁,然后创建出FileOutputStream为输出通道,

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第15张图片


Java NIO中的FileChannel是一个连接到文件的通道。可以通过文件通道读写文件。

FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下。

这里的FileChannel是FileOutputStream中获取的通道的。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第16张图片

这里面需要释放的时候,需要释放Filelock,FileChannel, FileOutStream, File,四个对象形成的锁。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第17张图片

当正常安装以后,了通过获取到PluginInInfo来判断插件是否成功安装

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第18张图片

然后再次下载中会通过onPluginNotExitsForActivtiy,来回调提示。

如果activity是动态注册的类,直接使用startActivity打开

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第19张图片

这里面需要判断插件中有注册到注册的Activity类

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第20张图片

这里是通过HashMap来保存类的列表

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第21张图片

这里其他插件首先会在Entry的入口里面在init的时候调用注册的方法注册,创建出一个ProxyRePluginVar的远程插件信息。

其会创建出两个startActivity的MethodInvoker反射的类,来用于使用跳转方法。其会分发到不同的插件的RePlugin的对象

Broadcast,Provider,Service,四大组件都是通过这种反射调用的方式,来提供其他插件调用的。


回到PmInternalImpl,插件损坏或者其他原因状态异常,判读会返回跳转目标不存在

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第22张图片


如果是大插件,会使用onLoadLargePluginForActivity的方法启动。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第23张图片

这里真正的启动占坑的方式来做跳转

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第24张图片

我们看到loadPluginActivity当中,通过ActivityInfo 来保存一个Activity的信息,然后

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第25张图片

这里判断进程和远程分配坑位。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第26张图片

如果有分配,立刻进入监控状态,并强制使用UI进程运行。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第27张图片

使用bindActivity来绑定Activity.

bindActivity当中,继续调用到PluginContainter的alloc分配

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第28张图片

最终会调用到allocLocked分配,里面有四种规则

(1)尝试找找到一个动态注册过的。

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第29张图片

(2)找一个新分配的

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第30张图片

(3)重用,最老的一个

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第31张图片

(4)挤掉最老的一个

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第32张图片

然后通过坑位跳转

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第33张图片

我们在plugin-lib中的插件需要依赖的库中找到

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第34张图片

其PluginActivity是替换的Activity

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第35张图片

但是实际上demo中并没有使用继承PluginActivity的例子。都是使用占坑逻辑来替换,并不一定要使用PluginActivity。使用PluginActivity是嵌套生命周期的方法给Repluin管理。

Replugin占坑跳转的判断是我研究插件化以来最复杂的,代码量也很大。


我建立了一个关于Android架构学习的群,里面可以进一步进行组件化学习的交流。

群号是316556016,也可以扫码进群。我在这里期待你们的加入!!!

[Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?_第36张图片

你可能感兴趣的:([Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?)