OHOS标准系统的SAMGR代码解读(v3.1)--2--samgr 原创 精华

liangkz_梁开祝
发布于 2022-9-7 09:48
浏览
5收藏

::: hljs-center

OHOS标准系统的SAMGR代码解读(v3.1)–2–samgr

梁开祝 20220907
:::

前文:
OHOS标准系统的SAMGR代码解读(v3.1)–0–前言
OHOS标准系统的SAMGR代码解读(v3.1)–1–safwk

  OHOS标准系统的samgr组件位于3.1分支代码的//foundation/distributedschedule/samgr/目录下,在最新的master分支代码则是//foundation/systemabilitymgr/samgr/目录下。

1. samgr 组件的全景图

先看samgr组件的全景图(附件有大图)
OHOS标准系统的SAMGR代码解读(v3.1)--2--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交互示意图进行理解。
OHOS标准系统的SAMGR代码解读(v3.1)--2--samgr-鸿蒙开发者社区

3. samgr 服务端的类结构

  samgr 服务端主要的类结构和继承关系,见全景图的右下角以ohos_executable(“samgr”)为起点的部分。

3.1 SA死亡回调相关的成员和RPC回调相关的成员

  在 SystemAbilityManager::Init() 中创建并初始化的与SA死亡回调相关的成员、RPC回调相关的成员,这里先放下不说,请小伙伴先自行阅读代码理解。

3.2 SystemAbilityLoadCallbackProxy 和 SystemAbilityStatusChangeProxy

  在 SystemAbilityManager 类提供的服务中,samgr会根据需要调用相关的接口向samgr_proxy发送IPC消息,以此向Proxy反馈SA的加载状态、上线离线状态等信息,见4.2节的简介。

3.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”)为起点的部分。

4.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);
    ......
}

4.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 就可以收到该消息并做针对性地处理。

4.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交互

  一图胜千言,两图胜两千言。

  请结合前面两张图自行阅读代码进行理解。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
samgr--全景图和进程间通信示意图.rar 2.31M 239次下载
已于2022-9-7 09:48:35修改
5
收藏 5
回复
举报
7条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

文中图看不清的小伙伴可以下载附件,附件中有高清大图。

回复
2022-9-7 10:18:56
FlashinMiami
FlashinMiami

有图表还是比读文字舒服多了

回复
2022-9-7 16:04:33
liangkz_梁开祝
liangkz_梁开祝 回复了 FlashinMiami
有图表还是比读文字舒服多了

字不如表,表不如图!

1
回复
2022-9-7 17:12:07
wx62f9e04f8237b
wx62f9e04f8237b

大佬,书出版了吗?有电子版的吗,最近在学习这部分代码,有偿!

回复
2022-9-9 14:15:54
liangkz_梁开祝
liangkz_梁开祝 回复了 wx62f9e04f8237b
大佬,书出版了吗?有电子版的吗,最近在学习这部分代码,有偿!

纸质书已经在出版社排版印刷了,预计下个月可上市。是否出电子版由出版社确定,目前暂不能提供。

“最近在学习这部分代码”如果是指分布式任务调度子系统,在我的专栏里就有分析这部分代码的一组博文,对你应该有所帮助。

2
回复
2022-9-9 16:29:25
wx631807b2aa6b8
wx631807b2aa6b8

想问一个问题,“samgr服务在OHOS系统中几乎是最早启动的系统服务”,请问这里说到的系统服务就是系统能力SA的意思吗?如果不是,请问系统服务和系统能力的区别是什么?

samgr比safwk先启动吗?

回复
2022-10-5 00:09:34
liangkz_梁开祝
liangkz_梁开祝 回复了 wx631807b2aa6b8
想问一个问题,“samgr服务在OHOS系统中几乎是最早启动的系统服务”,请问这里说到的系统服务就是系统能力SA的意思吗?如果不是,请问系统服务和系统能力的区别是什么?samgr比safwk先启动吗?

    这里的系统服务就是指系统能力(System Ability),在OHOS中,所有的系统能力都是以服务的形式来对外提供服务(能力、功能、接口)的,所以系统能力也称为系统服务。在master分支代码上,原先的distributedschedule子系统已经改名为systemabilitymgr子系统,而samgr和safwk都是该子系统的组件。

    safwk自己并不能作为一个单独或独立的进程来运行,它是一个或多个服务(如标准系统的dsoftbus服务)运行起来的框架(或躯壳),它为服务进程创建或提供运行起来的基础环境。服务自己的动态链接库(如dsoftbus的 libsoftbus_server.z.so)则是服务通过safwk加载并运行起来后要去运行的主体(或灵魂)。

    正常情况下,一定是samgr先启动和运行起来,其它的服务(不管是否通过safwk启动)需要向samgr注册SA。如果其它服务通过safwk先于samgr运行起来,则该服务会在获取samgrProxy这一步失败,然后会马上终止启动,返回异常而退出。该服务进程的父进程(Init进程)收到子进程异常退出信号之后,会尝试重新启动该服务。一般来说samgr启动起来之后,别的服务就可以获取samgrProxy并正常注册SA了。


    我说“samgr服务在OHOS系统中几乎是最早启动的系统服务”,是因为确实还有比samgr更早启动的系统服务(如 ueventd),因为 ueventd 并不是普通意义上的系统服务,不需要向samgr注册SA才能工作(就是说这些服务不需要通过samgr的管理才能向系统提供服务)。

1
回复
2022-10-5 10:08:20
回复
    相关推荐