更多开源信息请访问:开源基础软件社区https:///ost.51cto.comOHOS标准系统的safwk组件位于3.1分支代码的//foundation/distributedschedule/safwk/目录下,最新的master分支代码在//foundation/systemabilitymgr/safwk/目录。使用tree命令打印出目录树结构,并去掉我们暂时不关心的测试相关代码和文件,结果如下图所示:通过三个BUILD可以看到safwk组件中的.gn文件、safwk组件的配置文件和源代码编译成以下三个目标:配置文件profile。可执行程序sa_main。动态链接库文件system_ability_fwk(即libsystem_ability_fwk.z.so)。让我们来看看它们中的每一个。1、配置文件profile在3.1发布分支代码的safwk/etc/profile/目录下,只有BUILD.gn和foundation_trust.xml两个文件(foundation.cfg文件其实在//foundation/appexecfwk/standard/sa_profile/目录)。在master分支代码的safwk/etc/profile/目录下,除了BUILD.gn、foundation_trust.xml和foundation.cfg之外,新增了一个foundation_permission_desc.json文件(新文件在BUILD.gn使用中没有看到).可以看出,这些配置文件在3.1版本和master分支之间略有差异,但不影响我们对safwk组件的分析。(1)foundation.cfg这是标准系统基础进程的启动配置文件。在标准系统的启动阶段,init进程解析/system/etc/init/foundation.cfg文件,执行其中的命令拉起foundation进程(实际上标准系统中有相当多的进程是以类似的方式拉起进程,搜索和过滤/system/etc/init/*.cfg文件以进行确认)。查看/system/etc/init/foundation.cfg文件:......(略)"services":[{"name":"foundation","path":["/system/bin/sa_main","/system/profile/foundation.xml"],......"jobs":{"on-start":"services:foundation"}}]标准系统的基础进程不会自己生成可执行程序,而是借用/system/bin/sa_main可执行程序创建并初始化foundation进程的运行环境,根据传入的/system/profile/foundation运行foundation.xml文件中指定的各个SA。xml参数,保证本组SA能够顺利的为系统提供服务。(2)foundation.xml/system/profile/foundation.xml文件由编译系统自动生成,由一组serviceid.xml合并而成。在foundation.xml中可以看到一组SAID,比如401、3501、4802等,我们可以在系统代码的根目录下搜索401.xml、3501.xml、4802.xml等来找到相应的文件。在这些文件中,可以看到一个“foundation”字段,说明这些SA运行在foundation进程空间,“xxx”之间的字段是详细配置启动SA时会用到SA的信息(这些配置信息的详细信息请参考safwk/README_zh.md文档)。(3)foundation_trust.xml和foundation_permission_desc.jsonfoundation_trust.xml记录了foundation进程可以加载运行的SA列表,见4.1节分析。foundation_permission_desc.json当前未使用。(4)其他进程的.cfg和.xml如果其他进程也使用sa_main可执行程序拉起该进程,则它们也必须有相应的.cfg和serviceid.xml文件。例如,softbus_server进程将有dsoftbus/core/frame/standard/init/src/softbus_server.cfg和dsoftbus/core/frame/standard/sa_profile/4700.xml。这两个文件经过编译系统处理后,对应生成系统中的/system/etc/init/softbus_server.cfg和/system/profile/softbus_server.xml。(《沉浸式剖析OpenHarmony源代码》的8.7.1节详细分析了softbus_server进程的启动过程,本文不再赘述。)2.可执行程序sa_main可执行程序sa_main由safwk/services/safwk/单独编译src/main.cpp文件生成。查看它的源码,可以发现它的实际工作非常简单:执行main()函数,创建并初始化系统中进程的运行环境;然后读取并解析.xml文件(如foundation.xml或softbus_server.xml),将进程名称设置为.xml文件中“name”字段指定的名称;finallyexecute:LocalAbilityManager::GetInstance().DoStartSAProcess(profilePath,saId);//注意:在系统启动阶段自动启动进程时,此时saId参数的值为-1,而不是传入特定的SAID。这将启动.xml文件中指定的一个或多个SA。3、动态链接库文件system_ability_fwksystem_ability_fwk动态链接库提供了sa_main启动具体SA的支持,其源代码、依赖关系、类间关系等,如下图所示:(1)组件依赖Pay注意库的依赖性。依赖于samgr相关的三个动态链接库,在解释samgr组件时会分析到。所依赖的ipc_core组件(对应上图右上角的一组虚基类)提供的IPC功能本文不再深入分析。(2)类的继承关系从上图蓝色底色部分灰色底色表示的三个类的关系可以看出:LocalAbilityManagerStub类继承了ILocalAbilityManager接口类,提供了服务端(stub))为启动SA接口,启动SA的具体通用流程(或公共流程)由其子类LocalAbilityManager实现。LocalAbilityManager类实现了启动SA的大致过程,记录了当前进程中所有SA的详细信息、当前LocalAbilityManager类对象、SA任务信息等。每个SA对应一个SystemAbility类的对象,记录了serviceid.xml文件中“xxx”字段记录的信息。LocalAbilityManager类是SystemAbility类的友元类,LocalAbilityManager类可以直接访问SystemAbility类的所有成员和函数。它们的关系如下图所示:4.启动SA的大致流程如上1.1所述。init进程读取并解析/system/etc/init/*.cfg文件,当启动到具体的jobs阶段时,执行相应的命令启动服务(即SA)。下面以softbus_server(SA4700)的启动为例,简单说明一下safwk组件相关的SA的大致启动流程。(1)DoStartSAProcess()函数sa_main可执行程序的执行流程如上图所示,其主要工作是调用以下函数的步骤。LocalAbilityManager::GetInstance().DoStartSAProcess(profilePath,saId);DoStartSAProcess()函数中的4个步骤简单解释如下:步骤[4-1]:调用InitSystemAbilityProfiles()函数主要是分析传入的main()第二个参数中指定的.xml文件,并分析和将文件的列表中记录的每个SA的信息一一提取出来,记录到ParseUtil类的以下两个字段中://当前进程的SA链表,链表上的每个节点是一个SaProfile结构体std::listsaProfiles_;//当前进程的名称,如foundation、softbus_server等std::u16stringprocName_;然后确认是否有“/system/profile/processname_trust.xml”文件(如1.3中提到的foundation_trust.xml文件)。如果文件存在,则通过CheckTrustSa()确认当前进程是否允许加载运行上述SA链表中的SA,删除当前进程不允许加载运行的SA来自SA链表。它不会在接下来的步骤中加载和运行。最后调用OpenSo()将SA链表中SA指定的动态链接库加载到当前进程的运行空间中。voidParseUtil::OpenSo(){for(auto&saProfile:saProfiles_){if(saProfile.runOnCreate){OpenSo(saProfile);}}}加载动态链接库时,会根据不同SA服务对象的类构造函数创建各自的SA,并执行SystemAbility::MakeAndRegisterAbility(Xxxobj)将SA的服务对象注册到std::map中用于备份的LocalAbilityManager类的abilityMap_成员。该成员是一个map数据结构,key为saId。值对应于特定的SA对象指针。步骤[4-2]:调用CheckSystemAbilityManagerReady()函数。这一步主要是通过尝试获取samgrProxy来确认是否可以访问远程samgr进程的saManager服务。samgr进程几乎是最早运行在用户空间的系统进程,所有的SA都需要依赖samgr提供的服务。步骤[4-3]:调用InitializeSaProfiles()函数这一步主要是执行InitializeRunOnCreateSaProfiles()函数,在abilityMap_中依次从SA链表(saProfiles_)中的SA中提取出匹配的SA,并根据字段配置,在LocalAbilityManager类的std::map>abilityPhaseMap_成员中添加SA。该成员是一个map数据结构,key是下面枚举中的一个值(表示不同的启动阶段):enum{BOOT_START=1,CORE_START=2,OTHER_START=3,};value是一个链表的链表结构,链表上的每个节点都是SA的一个对象指针。当系统启动到枚举指定的阶段时,将依次启动list列表中的所有SA。启动阶段:可选;可以设置三个值:BootStartPhase、CoreStartPhase、OtherStartPhase(默认类型),三个优先级依次降低。在同一个过程中,会先激活注册和配置BootStartPhase的SystemAbility,然后再配置CoreStartPhase。SystemAbility,最后是OtherStartPhase;当所有高优先级的SystemAbility都启动并注册完成后,才会开始注册下一级SystemAbility。步骤[4-4]:调用Run()函数。该步骤调用Run()函数向saManager注册SA,并启动SA对应的任务。(2)Run()函数LocalAbilityManager::Run()的过程(见附图大图),按照函数调用分为以下5个步骤,简单分析如下。步骤[5-1]:向远程samgr注册当前进程的localAbilityManager_对象。这一步首先获取远程samgr的服务代理,通过代理向saManager发送IPC消息,将当前进程的名称和进程的localAbilityManager_对象注册到samgr中的std::map>systemProcessMap_成员,该成员是一个map数据结构,key是进程名字符串,value是进程的localAbilityManager_对象(也是一个IRemoteObject对象)。步骤[5-2]:启动当前进程的主线程步骤[5-3]:按照启动的阶段依次启动abilityPhaseMap_中对应阶段的SA链表中的各个SA。这一步相当于SA的优先级依次启动进程中的每个SA。比如foundation进程有若干个SA,一部分在CORE_START阶段启动,另一部分在默认的OTHER_START阶段之后启动;而softbus_server进程只有一个SA4700,默认在OTHER_START阶段启动。进程中的每个SA都会在当前进程中创建一个任务(线程),并将任务的入口函数绑定为LocalAbilityManager::StartSystemAbilityTask()。任务启动后执行该函数,首先确认SA的依赖关系,然后进入启动各个具体SA的过程(如上图启动软总线SA的过程,这是其独有的启动过程部分每个SA)。步骤[5-4]:将标记为按需启动的当前进程的SArun-on-create注册到远程samgr:true表示进程启动后,SystemAbility将注册到samgr组件;false表示按需启动,即在其他模块访问SystemAbility时要求启动。这一步首先获取远程samgr的服务代理,通过代理向saManager发送IPC消息,将当前进程的名称和按需启动的SA的id注册到std::maponDemandAbilityMap_samgr的成员其中,该成员是一个map数据结构,key是按需启动的SA的id,value是SA所在进程的进程名。注意:此时按需启动的SA还没有启动,即还没有执行步骤[5-3]的过程为SA创建任务。当其他进程向saManager查询按需SA时,saManager会通过pendingTask执行StartOnDemandAbility()函数的过程向SA所在进程发送IPC消息,请求启动SA,如图绿色上图右下角的部分。步骤[5-5]:停止当前进程的主线程(3)启动按需SAsaManager,向SA所在进程发送IPC消息。到IPC消息,并进一步处理,如下图右半部分所示。LocalAbilityManagerStub通过其子类的LocalAbilityManager::StartAbility()进程启动对应的SA。StartAbility()首先创建一个任务运行LocalAbilityManager::StartOndemandSystemAbility()加载SA对应的动态链接库,然后执行OnStartAbility()启动SA,最后进入启动具体SA(也就是SA自己的)的过程独特的启动过程)。5.总结以上就是safwk启动SA的大致流程。safwk组件还提供了一些其他功能,如添加、通知、删除SA监听器,退出SA到samgr等,请自行阅读源码了解。文章相关附件可点击下方原文链接下载:https://ost.51cto.com/resource/2283。了解更多开源知识,请访问:开源基础软件社区https://ost.51cto.com。