插件化框架解读之四大组件调用原理-Service(三)下篇(1)

// 2. 获取将要使用服务的进程ID,
int process = getProcessByComponentName(cn);
if (process == PROCESS_UNKNOWN) {
// 有可能是不支持的插件,也有可能本意就是想调用Main工程的服务。则直接调用系统方法来做
if (LOG) {
LogDebug.d(PLUGIN_TAG, “PSS.startService(): Call SystemAPI: in=” + intent);
}
if (throwOnFail) {
throw new PluginClientHelper.ShouldCallSystem();
} else {
return context.startService(intent);
}
}

// 既然确认是插件,则将之前获取的插件信息填入
intent.setComponent(cn);

//3. 获取对应进程ID的IPluginServiceServer对象,IBinder实现提是PluginServiceService.Stub
IPluginServiceServer pss = sServerFetcher.fetchByProcess(process);
if (pss == null) {
if (LOGR) {
LogRelease.e(PLUGIN_TAG, “psc.ss: pss n”);
}
return null;
}

// 开启服务
try {
return pss.startService(intent, sClientMessenger);
} catch (Throwable e) {
if (LOGR) {
LogRelease.e(PLUGIN_TAG, “psc.ss: pss e”, e);
}
}
return null;
}

第3步
重点看下如果根据不同进程去生成相应的PSS对象,也就是方法sServerFetcher.fetchByProcess方法

public IPluginServiceServer fetchByProcess(int process) {
if (process == PluginServiceClient.PROCESS_UNKNOWN) {
return null;
}
// 取之前的缓存
IPluginServiceServer pss;
synchronized (PSS_LOCKER) {
pss = mServiceManagerByProcessMap.get(process);
if (pss != null) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, “PluginServiceClient.fsmbp(): Exists! p=” + process);
}
return pss;
}
}

// 缓存没有?则去目标进程获取新的
if (LOG) {
LogDebug.d(PLUGIN_TAG, “PluginServiceClient.fsmbp(): Create a new one! p=” + process);
}
try {
if (process == IPluginManager.PROCESS_PERSIST) {
//1. 如果是常驻进程,则直接获取得到Pss对象,PluginServiceServer.mStub
IPluginHost ph = PluginProcessMain.getPluginHost();
pss = ph.fetchServiceServer();
} else {
//2. 如果是非常驻其他进程,则会通过 MP.startPluginProcess方法,利用动态编译自动生成的进程挂在宿主Manifest中的Provider
//去通过PluginProviderStub.proxyStartPluginProcess 利用insert方法去吊起provider对应的进程号,开启进程
//IPluginClient的实现体就是PluginProcessPer中,获得对象同样是PluginServiceServer.mStub
PluginBinderInfo pbi = new PluginBinderInfo(PluginBinderInfo.NONE_REQUEST);
IPluginClient pc = MP.startPluginProcess(null, process, pbi);
pss = pc.fetchServiceServer();
}

// 挂死亡周期,如果出问题了就置空重来,防止外界调用psm出现DeadObject问题
pss.asBinder().linkToDeath(new PSSDeathMonitor(process, pss.asBinder()), 0);
} catch (Throwable e) {
if (LOGR) {
LogRelease.e(PLUGIN_TAG, “psc.fsm: e”, e);
}
}
if (pss != null) {
synchronized (PSS_LOCKER) {
mServiceManagerByProcessMap.put(process, pss);
}
}
return pss;
}

  1. 显然,针对不同进程号,使用了一个ArrayMap来缓存对应pss对象,如果是常驻进程,也就是进程号

process == IPluginManager.PROCESS_PERSIST

会直接获得PluginServiceServer.mStub的IPluginServiceService对象来进行相关Service操作。

  1. 如果Service所处的是非常驻进程,这里会采用一个比较巧妙的方法去首先拉起该进程,跟踪下面方法:

IPluginClient pc = MP.startPluginProcess(null, process, pbi);

MP.java

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

显然,会调用常驻进程服务的PmHostSvc.startPluginProcess方法去拉起对应进程,PmHostSvc常驻进程服务再整个Replugin确实起到了对各插件管理的作用,包括拉起插件Service进程。继续往下看,调用了PmBase.startPluginProcessLocked方法:

final IPluginClient startPluginProcessLocked(String plugin, int process, PluginBinderInfo info) {

PluginProcessMain.schedulePluginProcessLoop(PluginProcessMain.CHECK_STAGE1_DELAY);

// 尝试从缓存中查找
IPluginClient client = PluginProcessMain.probePluginClient(plugin, process, info);

int index = IPluginManager.PROCESS_AUTO;
try {
index = PluginProcessMain.allocProcess(plugin, process);
} catch (Throwable e) {
}
// 启动
boolean rc = PluginProviderStub.proxyStartPluginProcess(mContext, index);

// 再次获取
client = PluginProcessMain.probePluginClient(plugin, process, info);

return client;
}

PluginProviderStub.proxyStartPluginProcess方法去会吊起对应进程,代码如下:

PluginProviderStub.java

static final boolean proxyStartPluginProcess(Context context, int index) {
//
ContentValues values = new ContentValues();
values.put(KEY_METHOD, METHOD_START_PROCESS);
values.put(KEY_COOKIE, PMF.sPluginMgr.mLocalCookie);
Uri uri = context.getContentResolver().insert(ProcessPitProviderBase.buildUri(index), values);
if (LOG) {
LogDebug.d(PLUGIN_TAG, “proxyStartPluginProcess insert.rc=” + (uri != null ? uri.toString() : “null”));
}
if (uri == null) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, “proxyStartPluginProcess failed”);
}
return false;
}

return true;
}

这里是个对数据库Provider的插入操作,那么究竟是对哪个Provider进行了数据库操作呢?

关键在这里:

ProcessPitProviderBase.buildUri(index)

最终生成的Uri是这样的:

content://com.qihoo360.replugin.sample.host.loader.p.mainN99/main

这个玩意对应的啥呢?貌似宿主Manifest中并没有配置这个,如果分析过gradle插件应该可以想到,估计又是动态编译自动生成的,反编译宿主apk可以在Manifest中发现:

这样就全部串起来啦,想要开启分配在自定义进程中的Service首先就需要通过启动动态编译自动生成的对应进程Provider来拉起进程。
最终返回的IPluginClient的IBinder实现体其实就是PluginProcessPer,生成的PSS也就是PluginServiceServer.mStub了。跟上述常驻进程生成的PSS方式是一样的。

第4步
PSS中startService最终调用的是PluginServiceServer.this.startServiceLocked(intent,client)方法,其内部首先通过retrieveServiceLocked方法生成ServiceRecord对象,接着利用installServiceIfNeededLocked方法去加载Service对象,利用发射将PluginContext通过attachBaseContextLocked方法赋值到上下文内部,接着执行Service的onCreate方法,然后记录以及被加载,同时startPitService开启一个坑位Service,提高进程优先级防止被杀,后面继续调用onStartCommand方法。

// 加载插件,获取Service对象,并将其缓存起来
private boolean installServiceLocked(ServiceRecord sr) {
// 通过ServiceInfo创建Service对象
Context plgc = Factory.queryPluginContext(sr.plugin);
if (plgc == null) {
if (LogDebug.LOG) {
Log.e(TAG, “installServiceLocked(): Fetch Context Error! pn=” + sr.plugin);
}

如何做好面试突击,规划学习方向?

面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。

学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。

我们搜集整理过这几年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。

img

我们在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
络 + 分支细节。

[外链图片转存中…(img-hKzLDByc-1715316596976)]

我们在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 9
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值