Hi3516之SAMGR--系统服务框架子系统-6-系统服务的启动在进入正题之前,先简单了解一下轻量级系统和小型系统(包括标准系统,同后者)在系统服务方式方面的区别开始了。无论是轻量级系统还是小型系统,系统服务和特性(service/feature)的Init函数都会被标记为一组宏,如SYS_SERVICE_INIT/SYS_FEATURE_INIT或SYSEX_SERVICE_INIT/APP_SERVICE_INIT/SYSEX_FEATURE_INIT/APP_FEATURE_INIT,定义在//utils/native/lite/include/ohos_init.h文件。打开这个文件,可以看到:在“LAYER_INITCALL”宏的展开中,开始了轻量级系统和小型系统的区别。命令行进入B_LTS项目代码根目录,执行$find./-name*.gn|xargsgrep-in"LAYER_INIT_SHARED_LIB"命令,可以在//foundation/distributedschedule/samgr_lite/samgr/BUILD.gn:14中找到"LAYER_INIT_SHARED_LIB"的定义。打开看看:config("external_settings_shared"){defines=["LAYER_INIT_SHARED_LIB"]}if(ohos_kernel_type=="liteos_m"){static_library("samgr"){...}}if(ohos_kernel_type=="liteos_a"||ohos_kernel_type=="linux"){shared_library("samgr"){......public_configs+=[":external_settings_shared"]}}也就是说轻量级系统没有定义"LAYER_INIT_SHARED_LIB",而小系统则包含了这个宏的定义。为什么要把“LAYER_INIT_SHARED_LIB”的定义放在samgr_lite/samgr组件上,后面会提到。轻量级系统:在轻量级系统上,LAYER_INITCALL使用__attribute__((section("section_name")))进行扩展,其作用是在编译阶段中将函数或数据链接到名为“section_name”的指定section。系统启动时,使用MODULE_INIT/SYS_INIT宏找到“section_name”对应的section中记录的入口函数,依次执行。注意这个启动方式是串行的。上一个服务的入口函数还没有执行,下一个服务的入口函数也不会执行。这意味着你不能在SYS_SERVICE_INIT/SYS_FEATURE_INIT等宏标记的入口函数中做太多的事情。特别是你不能做阻塞事情的原因。更具体的启动详情,请前往《Hi3861_WiFiIoT工程的一点理解》阅读理解。小系统:在小系统上,LAYER_INITCALL使用__attribute__((constructor))进行扩展,对应的还有一个__attribute__((destructor)),类似于C++类中构造函数和析构函数的作用。如果将函数设置为constructor属性,则该函数会在main()函数开始执行之前自动执行;如果函数被设置为destructor属性,则该函数将在main()函数执行后执行或调用后自动执行exit()。这在小型系统中非常有用。比如某个进程的运行依赖于ServiceA和FeatureAa。ServiceA和FeatureAa的Init函数标有SYS_SERVICE_INIT/SYS_FEATURE_INIT。那么,在进程启动时执行main函数之前,ServiceA和FeatureAa的Init函数都会先于main函数执行。因此,在小型系统中,梳理关键进程的服务依赖关系非常重要。下面进入正题,小系统系统服务的整体启动流程。我们知道,鸿蒙系统是从内核态切换到用户态的。第一个运行的进程Init也称为用户态根进程。它读取并分析/etc/init.cfg配置文件(//vendor/hisilicon/hispark_taurus/init_configs/init_liteos_a_3516dv300.cfg),根据上面的记录,依次启动几个关键的系统进程:{"name":"init“,“cmds”:[“startshell”,“startapphilogcat”,“startfoundation”,“startbundle_daemon”,“startappspawn”,“startmedia_server”,“startwms_server”,“starthiview”,“startsensor_service”,“startai_server”]},系统启动日志如下:Here"[init_service]ServiceStart:[[xxxx]]:OK,pid[x]."只是说明用户态根进程已经为服务进程创建了运行基础环境,并获得了服务进程的Pid,但并不代表服务进程可以正常工作,服务进程需要执行自己的main()函数运行,在此之前,需要先运行它所依赖的“ServiceA和FeatureAa”的所有__attribute__((constructor))函数,然后是main(),最后一步一般是进入while(1){pause()}状态,即服务进程进入后台,默默守护进程及其所有子进程/子线程,有点像蜂王/蜂王,进程对服务,内部/外部提供的功能、接口等具体工作由其后代完成。如上所述,一个服务进程对其他进程的依赖是非常重要的。下表是对上面initOK的9个进程的依赖关系进行了一些整理,逐层列出了各个进程的依赖关系,从上到下,三方库的依赖和重复的依赖都变灰了,这样看起来就干净多了。【每次重新刷整理,发现会有一些小遗漏,所以这张表并不完美】从系统启动完整过程的log来看,这9个进程的实际启动顺序和给出的是一样的在/etc/init.cfg上面顺序不是一一对应的:Line167:{Process:shell}Line170:{Process:apphilogcat}Line182:{Process:sensor_service}Line195:{Process:bundle_daemon}Line284:{Process:ai_server}Line345:{Process:wms_server}Line347:{Process:media_server}Line573:{Process:foundation}Line1678:{Process:appspawn}这是因为有些进程的依赖很少,所以启动速度更快,而基础进程依赖关于很多事情,所以他们开始得更快很慢。前面提到“为什么要把LAYER_INIT_SHARED_LIB的定义放在samgr_lite/samgr组件上”,因为轻量级系统没有使用__attribute__((constructor))的机制,所以LAYER_INIT_SHARED_LIB的定义放在哪里是无所谓的;对于小系统,看上面的依赖表,shell/apphilogcat/media_server这三个进程不依赖其他ServiceA和FeatureAa,也不依赖samgr组件,所以对于它们来说,LAYER_INIT_SHARED_LIB的定义放在哪里都无所谓;而其他进程需要依赖samgr,进程依赖的所有ServiceA和FeatureAa都由samgr管理和启动,所以把LAYER_INIT_SHARED_LIB的定义放在samgr中最底层是非常合适的,可以降低耦合度系统组件的程度降到最低。3号进程shell由内核提供,直接启动。这是完整的shell,代码位于//kernel/liteos_a/shell/full/目录中。4号进程apphilogcat有一个非常简单的依赖。它只依赖第三方库和//base/hiviewdfx/hilog_lite/frameworks/featured/目录下的代码编译的动态链接库hilog_shared,所以也是直接启动的。5号进程的基础依赖的东西很多,后面需要跑到main函数,后面会详细介绍。反之,10号进程sensor_service、6号进程bundle_daemon、11号进程ai_server,依赖比较简单,先跑完依赖,进入while(1){pause()}。9号进程wms_server启动后,其子线程会不停地监听按键/屏幕触摸等输入或窗口显示事件并做出响应。8号进程media_server,mediaservice进程看起来最干净,只有//device/hisilicon/hardware/multimedia:libhdi_media支持,最后支持liteos_a:kernel。7号进程appspawn是最后一个启动的系统进程。它醒来后,可以孵化第一个应用进程launcher和其他后续应用进程。以上shell/apphilogcat/media_server这三个进程不依赖samgr,也不依赖其他Service/Feature,这里不多说。其他6个系统进程,每个进程都有自己独立的地址空间,不能直接相互访问,需要通过进程间通信进行交互。一个独立的系统进程,在自己独立的地址空间,启动它所依赖的Service/Feature,由自己空间的SamgrLiteImplg_samgrImpl管理。它是一个独立的轻量级系统。你可以在这里阅读我之前的文章《Hi3861的SAMGR--系统服务框架子系统-3》,但请注意,还是有一些很大的不同。下面以不太简单但也不复杂的wms_server进程为例进行分析。打开//foundation/graphic/wms/BUILD.gn文件,查看其依赖关系,简化如下:hdi_input/lite_graphic_hals,需要外围硬件设备的支持,在硬件驱动启动时加载运行。samgr和lite_ipc_adapter都没有__attribute__((constructor))修改。这是两个独立的动态链接库,加载后可以直接使用。注意这里只是samgr本身,并没有包含"samgr_server:server"和"samgr_client":client"。Broadcast服务包含了"Providerandsubscriber"特性,但是好像并没有真正用到wms_server进程同样依赖于流程代码中提供的WMS/IMS服务,没有Feature,整理表如下:从上表的依赖关系来看,依赖于一个广播组件提供的Service/Feature,而自身wms_server组件提供的服务:WMS/IMS,所以从实际运行日志可以验证,在main()运行之前,__attribute__((constructor))修饰的Servic/Feature的Init函数先运行:在main之前函数运行,在wms_server进程的地址空间中,已经有进程的SamgrLiteImpl控制的文件g_samgrImpl静态展开图(展开图这里就不展示了,und的展开图可以参考《Hi3861的SAMGR--系统服务框架子系统-2》理解)。在main()中,运行HiFbdevInit()/InitDriver()后,会通过HOS_SystemInit()调用SAMGR_Bootstrap()函数,为以上三个服务创建各自的TaskPool、Task和Queue:Broadcast/WMS/IMS,其中WMS/IMS和SHARED_TASK是同级的,所以他们共享一个Task/Queue,在收发消息的时候会通过ServiceID来区分。Task运行后,会立即监听自己的消息队列,对消息进行处理。三个服务:Broadcast/WMS/IMS消息队列,每个都会先收到一个MSG_DIRECT消息,由HandleInitRequest()处理。在此HandleInitRequest()中,将调用DEFAULT_Initialize(serviceImpl)来初始化服务/功能。DEFAULT_Initialize(serviceImpl)函数中的行为,对于轻量级系统来说,就是调用Service/Feature生命周期函数Initialize()/OnInitialize()完成初始化工作,就OK了。SAMGR_RegisterServiceApi()函数是一个空存根函数。但是对于小系统,SAMGR_RegisterServiceApi()还有另外一个实现,这是一个新世界的入口。这里我们先说到这里,以后再详细讲。至此,系统服务进程wms_server可以开始工作了。在“[wms.cpp]main[5-4]:GetInstance()->Run()”这一步,InputManagerService实例对象开始无休止地监听和响应按钮/屏幕触摸等输入事件。"[wms.cpp]main[5-5]:while(1)"这一步也是通过"OHOS::LiteWM::GetInstance()->MainTaskHandler();"开始根据需要无限重绘窗口显示内容。其他五个进程的启动情况相似,或更简单,或更复杂,但都运行相似的进程。在每个进程内部,进程中的Service/Feature由自己的SamgrLiteImplg_samgrImpl管理,进程Threads内部的Service可以直接通过消息队列机制进行通信。如果要跨进程交互,就需要更复杂的机制。更多信息请访问:Harmonyos.51cto.com,与华为官方合作打造的鸿蒙技术社区
