OHOS标准系统的samgr组件位于3.1分支代码的//foundation/distributedschedule/samgr/目录下,在最新的master分支代码则是//foundation/systemabilitymgr/samgr/目录下。
1、samgr 组件的全景图
先看samgr组件的全景图(附件有大图)。
从上图中的代码目录结构和编译脚本部分,可以看到5个编译目标以及它们各自编译的代码:
- samgr_common:公共部分,提供SA Profile的解析工具、动态链接库的加载和卸载等功能,主要用在上一篇分析的safwk的工作流程中,本文不再赘述。
- lsamgr:local samgr的客户端代理,主要用于按需启动指定的SA;该功能也同时编译进samgr_proxy模块中(一并在samgr_proxy中分析)。
- samgr_proxy:samgr的客户端代理。SA通过该代理提供的接口与samgr服务进行交互,同时也为samgr服务向SA客户端反馈SA的加载结果、订阅的SA的状态变化等功能提供Stub接口。
- samgr_init:samgr服务自启动的配置文件,与samgr可执行程序配套使用。
- samgr:samgr服务的可执行程序实体,结合samgr_init的配置,在系统启动的早期自动运行,拉起samgr服务。同时也通过Proxy向SA客户端反馈SA的加载结果、订阅的SA的状态变化事件等消息。
全景图中虽然画出了IPC相关的结构,但本文暂不深入IPC/RPC的分析,因此,下文重点看samgr服务的实现和samgr_proxy客户端的实现。
2、samgr 服务的启动流程
samgr服务在OHOS系统中几乎是最早启动的系统服务,它在OHOS中占据了通信中枢的重要位置(可以参考我分析的samgr_lite系列文章来进行理解)。
samgr服务的启动流程如全景图左下角部分所示,看起来还是比较简单的。
在完成 SystemAbilityManager 类对象manager的创建和Init()之后,就生成了全景图右下角部分所示的结构;然后通过IPCSkeleton::SetContextObject()将 manager 作为远程对象注册到IPC模块,为以后的IPC/RPC提供IRemoteObject;最后samgr服务的主线程进入loop,开始为整个系统中的SA提供服务。
接下来的内容,请结合samgr组件的全景图和下面的IPC交互示意图进行理解。
3、samgr 服务端的类结构
samgr 服务端主要的类结构和继承关系,见全景图的右下角以ohos_executable(“samgr”)为起点的部分。
(1)SA死亡回调相关的成员和RPC回调相关的成员
在 SystemAbilityManager::Init() 中创建并初始化的与SA死亡回调相关的成员、RPC回调相关的成员,这里先放下不说,请小伙伴先自行阅读代码理解。
(2)SystemAbilityLoadCallbackProxy 和 SystemAbilityStatusChangeProxy
在 SystemAbilityManager 类提供的服务中,samgr会根据需要调用相关的接口向samgr_proxy发送IPC消息,以此向Proxy反馈SA的加载状态、上线离线状态等信息,见4.2节的简介。
(3)SystemAbilityManagerStub 和 SystemAbilityManager
samgr服务端的主要工作在这两个类中。
在samgr进程启动过程中创建SystemAbilityManager对象时,在SystemAbilityManagerStub的构造函数中就会初始化一个 memberFuncMap_,将Stub要处理的消息代码与处理函数关联起来。
SystemAbilityManagerStub在接收到SystemAbilityManagerProxy发过来的IPC消息后,直接在memberFuncMap_中匹配消息代码,然后转为调用子类SystemAbilityManager的函数来做具体的服务工作,如有需要也会把处理结果返回给SystemAbilityManagerProxy。
3.1和3.2中的工作,也是由SystemAbilityManager类发起调用或者直接进行处理的。
4、samgr_proxy的类结构
samgr_proxy相关的类结构和继承关系,见全景图的中以ohos_shared_library(“samgr_proxy”)为起点的部分。
(1)LocalAbilityManagerProxy
LocalAbilityManagerProxy类提供了向指定进程发送IPC消息拉起按需启动的SA的Proxy接口,由指定进程中的LocalAbilityManagerStub接收消息,并执行动态拉起SA的具体动作(如上一篇分析4.3节分析所示)。
例如,不管是同设备内的进程还是跨设备的进程,在调用:
sptr<IRemoteObject> SystemAbilityManager::CheckSystemAbility(int32_t systemAbilityId, bool& isExist)
向samgr查询SA时,samgr会先在已启动的 abilityMap_ 中查找目标SA,能找到,则表明SA已经启动了;找不到,则继续在正在启动的 startingAbilityMap_ 中查找目标SA,能找到,则表明SA正在启动中;还找不到,则会尝试调用StartOnDemandAbility(SAID)来启动目标SA(即按需启动SA)。StartOnDemandAbility(SAID)会在登记到onDemandAbilityMap_中的按需启动的SA列表中查找匹配SAID的记录,并通过SystemAbilityManager::StartOnDemandAbilityInner()向SAID所在进程发送IPC消息,要求该进程拉起对应的SA,如下代码片段所示:
void SystemAbilityManager::StartOnDemandAbilityInner(const std::u16string& procName, int32_t systemAbilityId,
AbilityItem& abilityItem)
{
......
//从 systemProcessMap_ 中获取 LocalAbilityManagerProxy procObject
sptr<ILocalAbilityManager> procObject =
iface_cast<ILocalAbilityManager>(GetSystemProcess(procName));
......
//调用 LocalAbilityManagerProxy::StartAbility
//向 LocalAbilityManagerStub 发送IPC消息拉起参数指定的SA
procObject->StartAbility(systemAbilityId);
......
}
(2)SystemAbilityLoadCallbackStub 和 SystemAbilityStatusChangeStub
当进程A向samgr注册SA_a时,samgr会调用:
void SystemAbilityManager::SendSystemAbilityAddedMsg(int32_t systemAbilityId, const sptr<IRemoteObject>& remoteObject)
{
......
auto notifyAddedTask = [systemAbilityId, remoteObject, this]() {
FindSystemAbilityNotify(systemAbilityId, ADD_SYSTEM_ABILITY_TRANSACTION);
NotifySystemAbilityLoaded(systemAbilityId, remoteObject);
};
bool ret = workHandler_->PostTask(notifyAddedTask);
......
}
其中的FindSystemAbilityNotify()会在 listenerMap_ 中查找监听SA_a状态变化的监听者,并调用listener的回调函数,通过SystemAbilityStatusChangeProxy向SystemAbilityStatusChangeStub发送SA_a上线或离线的消息。listener所在的进程B、进程C…的SystemAbilityStatusChangeStub就可以收到该消息并做针对性地处理。
其中的NotifySystemAbilityLoaded()也会通过SystemAbilityLoadCallbackProxy向SystemAbilityLoadCallbackStub 发送SA_a加载成功的IPC消息到查询SA_a的进程B中,这样进程B中的SystemAbilityLoadCallbackStub 就可以收到该消息并做针对性地处理。
(3)SystemAbilityManagerProxy和 SystemAbilityManagerClient
进程A必须要通过代理才能与samgr进行交互(如注册SA、查询SA等)。
如进程A在启动SA_a时,必须要先通过CheckSystemAbilityManagerReady() 确认samgr可以访问:
bool LocalAbilityManager::CheckSystemAbilityManagerReady()
{
......
//获取samgr的代理:SystemAbilityManagerProxy
sptr<ISystemAbilityManager> samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
while (samgrProxy == nullptr) {
HILOGI(TAG, "waiting for SAMGR...get 'samgrProxy'...");
if (timeout > 0) {
usleep(duration);
samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
} else {
HILOGE(TAG, "waiting for SAMGR...timeout[10s]...NGNGNG");
return false;
}
timeout--;
}
......
return true;
}
即能够成功获取samgr的代理SystemAbilityManagerProxy,这样SA_a才能注册到samgr中,否则表示samgr还没有能够正常工作,所有的SA_x都无法注册,所以可以说samgr进程是最早启动的系统服务进程了。
类似的,在系统中各个进程需要与samgr进行交互的时候,都是按下面这个流程进行的:
//先获取samgr的代理:SystemAbilityManagerProxy
sptr<ISystemAbilityManager> samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
//再通过该代理向samgr发送IPC消息,使用samgr提供的服务
samgrProxy->XxxYyy()
5、Proxy与Stub的IPC交互
一图胜千言,两图胜两千言。
请结合前面两张图自行阅读代码进行理解。
文章相关附件可以点击下面的原文链接前往下载:
https://ost.51cto.com/resource/2287。