Hi3516的SAMGR--系統(tǒng)服務(wù)框架子系統(tǒng)-6-系統(tǒng)服務(wù)的啟動(dòng)
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
在進(jìn)入正題之前,我們先來(lái)簡(jiǎn)單了解一下在系統(tǒng)服務(wù)的啟動(dòng)方式上,輕量系統(tǒng)和小型系統(tǒng)(包括了標(biāo)準(zhǔn)系統(tǒng),后面一樣)的差別。
不管是輕量系統(tǒng)還是小型系統(tǒng),系統(tǒng)服務(wù)和特性(service/feature)的Init函數(shù),都會(huì)用SYS_SERVICE_INIT /SYS_FEATURE_INIT或者SYSEX_SERVICE_INIT/APP_SERVICE_INIT/SYSEX_FEATURE_INIT/APP_FEATURE_INIT等一組宏來(lái)做標(biāo)記,這組宏定義在 //utils/native/lite/include/ohos_init.h文件內(nèi)。
打開這個(gè)文件,可以看到:

在對(duì)“LAYER_INITCALL”這個(gè)宏的展開上,輕量系統(tǒng)和小型系統(tǒng)的差別就開始了。
命令行進(jìn)入B_LTS項(xiàng)目代碼根目錄,執(zhí)行$find ./ -name *.gn | xargs grep -in "LAYER_INIT_SHARED_LIB" 指令,可以查到"LAYER_INIT_SHARED_LIB"定義的地方,在 //foundation/distributedschedule/samgr_lite/samgr/BUILD.gn:14。
打開看一下:
- 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" ]
- }
- }
也就是說(shuō)輕量系統(tǒng)沒(méi)有定義"LAYER_INIT_SHARED_LIB",而小型系統(tǒng)則是包含這個(gè)宏的定義的,為什么要將"LAYER_INIT_SHARED_LIB"的定義要放在samgr_lite/samgr組件上,這個(gè)稍后會(huì)講到。
輕量系統(tǒng):
輕量系統(tǒng)上,LAYER_INITCALL使用__attribute __((section(“section_name”)))來(lái)展開, 其作用是在編譯階段,將函數(shù)或數(shù)據(jù)鏈接到指定的名為"section_name"對(duì)應(yīng)的段中。在系統(tǒng)啟動(dòng)時(shí),再通過(guò)MODULE_INIT/SYS_INIT宏引導(dǎo)去"section_name"對(duì)應(yīng)的段中找到記錄的入口函數(shù),并依次執(zhí)行它們。
注意,這種啟動(dòng)方式是串行的,前一個(gè)服務(wù)的入口函數(shù)沒(méi)有執(zhí)行完,并不會(huì)執(zhí)行后一個(gè)服務(wù)的入口函數(shù),這就是不能在SYS_SERVICE_INIT /SYS_FEATURE_INIT等宏標(biāo)記的入口函數(shù)做太多事情、特別是不能做阻塞式的事情的原因。
更具體的啟動(dòng)細(xì)節(jié),請(qǐng)去《Hi3861_WiFiIoT工程的一點(diǎn)理解》進(jìn)行閱讀理解。
小型系統(tǒng):
小型系統(tǒng)上,LAYER_INITCALL使用__attribute __((constructor))來(lái)展開,對(duì)應(yīng)還有一個(gè)__attribute __((destructor)),它們就類似于C++的類中的構(gòu)造函數(shù)和析構(gòu)函數(shù)的作用。
- 如果函數(shù)被設(shè)定為constructor屬性,則該函數(shù)會(huì)在main()函數(shù)開始執(zhí)行之前被自動(dòng)地先執(zhí)行;
- 如果函數(shù)被設(shè)定為destructor屬性,則該函數(shù)會(huì)在main()函數(shù)執(zhí)行結(jié)束之后或者exit()被調(diào)用后,被自動(dòng)地執(zhí)行。
這在小型系統(tǒng)中非常有用,比如某個(gè)進(jìn)程的運(yùn)行依賴ServiceA和FeatureAa,ServiceA和FeatureAa的Init函數(shù)都用SYS_SERVICE_INIT /SYS_FEATURE_INIT標(biāo)記了,那在這個(gè)進(jìn)程啟動(dòng)時(shí)的main函數(shù)執(zhí)行之前,ServiceA和FeatureAa的Init函數(shù)就會(huì)先于main被執(zhí)行。所以,小型系統(tǒng)中,梳理清楚關(guān)鍵進(jìn)程的服務(wù)依賴關(guān)系就顯得非常重要了。
下面我們就進(jìn)入正題,小型系統(tǒng)的系統(tǒng)服務(wù)的整體的啟動(dòng)流程。
我們知道,鴻蒙系統(tǒng)從內(nèi)核態(tài)切換到用戶態(tài),跑的第一個(gè)進(jìn)程Init,也叫用戶態(tài)根進(jìn)程,它讀取并分析/etc/init.cfg配置文件(//vendor/hisilicon/hispark_taurus/init_configs/init_liteos_a_3516dv300.cfg的副本),根據(jù)上面的記錄,按順序啟動(dòng)幾個(gè)關(guān)鍵的系統(tǒng)進(jìn)程:
- {
- "name" : "init",
- "cmds" : [
- "start shell",
- "start apphilogcat",
- "start foundation",
- "start bundle_daemon",
- "start appspawn",
- "start media_server",
- "start wms_server",
- "start hiview",
- "start sensor_service",
- "start ai_server"
- ]
- },
系統(tǒng)啟動(dòng)的log如下:

這里的“[init_service] ServiceStart:[[xxxx]]:OK, pid[x].”僅僅表明用戶態(tài)根進(jìn)程已經(jīng)為服務(wù)進(jìn)程創(chuàng)建好了運(yùn)行的基礎(chǔ)環(huán)境并拿到了服務(wù)進(jìn)程的Pid,并不代表服務(wù)進(jìn)程已經(jīng)完全可以正常工作了。服務(wù)進(jìn)程需要去執(zhí)行自己的main()函數(shù)跑起來(lái),而在這之前,又需要先去跑完它依賴的所有的“ServiceA和FeatureAa”的__attribute __((constructor))函數(shù),然后main()的最后一步,一般是進(jìn)入while (1) { pause() }狀態(tài),也就是服務(wù)進(jìn)程進(jìn)入后臺(tái),默默守護(hù)著本進(jìn)程以及它的所有子進(jìn)程/子線程,有點(diǎn)像蜂王/蟻后一樣,進(jìn)程對(duì)內(nèi)/外提供的服務(wù)、功能、接口等具體工作,由它的子子孫孫來(lái)完成。
上面提到,一個(gè)服務(wù)進(jìn)程對(duì)別人的依賴關(guān)系非常重要,下表是我對(duì)上面init OK的9個(gè)進(jìn)程的依賴關(guān)系所做的一些梳理,把每一個(gè)進(jìn)程的依賴關(guān)系一層層找到列了出來(lái),從上到下,把對(duì)三方庫(kù)的依賴、重復(fù)出現(xiàn)的依賴,都灰化掉了,這樣看起來(lái)就清爽多了?!久看沃叵凑矶及l(fā)現(xiàn)會(huì)有一些小小的疏漏,所以這個(gè)表格還不算完美】

從系統(tǒng)啟動(dòng)完整過(guò)程的log看這9個(gè)進(jìn)程的實(shí)際啟動(dòng)順序與上面/etc/init.cfg給出的順序并不一一對(duì)應(yīng):
- Line 167: {Process:shell}
- Line 170: {Process:apphilogcat}
- Line 182: {Process:sensor_service}
- Line 195: {Process:bundle_daemon}
- Line 284: {Process:ai_server}
- Line 345: {Process:wms_server}
- Line 347: {Process:media_server}
- Line 573: {Process:foundation}
- Line 1678: {Process:appspawn}
這是因?yàn)橛行┻M(jìn)程依賴關(guān)系很少,就啟動(dòng)得快一些,而foundation進(jìn)程,依賴非常多的東西,所以啟動(dòng)得非常慢。
前面說(shuō)到“為什么要將 LAYER_INIT_SHARED_LIB 的定義要放在samgr_lite/samgr組件上”,因?yàn)檩p量系統(tǒng)不用__attribute __((constructor))這個(gè)機(jī)制,LAYER_INIT_SHARED_LIB的定義放在哪里,對(duì)輕量系統(tǒng)來(lái)說(shuō)無(wú)所謂;而小型系統(tǒng),看看上面的依賴關(guān)系表,shell/apphilogcat/media_server三個(gè)進(jìn)程不依賴其他的ServiceA和FeatureAa,也不依賴samgr組件,所以對(duì)它們來(lái)說(shuō),LAYER_INIT_SHARED_LIB的定義放在哪里,也無(wú)所謂;而其他進(jìn)程都需要依賴samgr,并且是由samgr來(lái)管理和啟動(dòng)該進(jìn)程所依賴的所有ServiceA和FeatureAa,所以LAYER_INIT_SHARED_LIB的定義,最低層次放在samgr是非常合適的,可以把系統(tǒng)組件的耦合程度降到最低。
3號(hào)進(jìn)程shell由內(nèi)核提供,直接啟動(dòng),這是full shell,代碼在//kernel/liteos_a/shell/full/目錄下。
4號(hào)進(jìn)程apphilogcat,依賴關(guān)系非常簡(jiǎn)單,僅僅依賴一個(gè)三方庫(kù)和由 //base/hiviewdfx/hilog_lite/frameworks/featured/ 目錄下的代碼編譯生成的動(dòng)態(tài)鏈接庫(kù)hilog_shared,所以也是直接啟動(dòng)了。
5號(hào)進(jìn)程foundation,依賴的東西非常多,需要到很后面才會(huì)跑到main函數(shù),這個(gè)后面詳細(xì)講。
反倒是依賴關(guān)系相對(duì)簡(jiǎn)單的10號(hào)進(jìn)程sensor_service、6號(hào)進(jìn)程bundle_daemon、11號(hào)進(jìn)程ai_server首先跑完依賴關(guān)系,進(jìn)入main的while (1) { pause() } 狀態(tài)。
9號(hào)進(jìn)程wms_server,啟動(dòng)起來(lái)之后,它的子線程就無(wú)休止地監(jiān)測(cè)按鍵/屏幕觸控等輸入性質(zhì)或者窗口顯示性質(zhì)的事件,并做出響應(yīng)。
8號(hào)進(jìn)程media_server,媒體服務(wù)進(jìn)程看上去是最干凈的,只由//device/hisilicon/hardware/multimedia:libhdi_media提供支持,最終由liteos_a:kernel提供支持。
7號(hào)進(jìn)程appspawn,是最后啟動(dòng)的系統(tǒng)進(jìn)程,它起來(lái)之后,就可以通過(guò)它孵化出第一個(gè)應(yīng)用進(jìn)程launcher,以及后面其他的應(yīng)用進(jìn)程。
上面shell/apphilogcat/media_server三個(gè)進(jìn)程不依賴于samgr,也不依賴于其他的Service/Feature,我們這里就先不說(shuō)了。
其他6個(gè)系統(tǒng)進(jìn)程,每個(gè)進(jìn)程都有自己獨(dú)立的地址空間,互相之間不能直接訪問(wèn),需要通過(guò)進(jìn)程間通信來(lái)進(jìn)行交互。
獨(dú)立的系統(tǒng)進(jìn)程,在自己獨(dú)立的地址空間內(nèi),啟動(dòng)自己所依賴的Service/Feature,由自己空間內(nèi)的SamgrLiteImpl g_samgrImpl來(lái)管理,完全就是一個(gè)獨(dú)立的輕量系統(tǒng),這里可以去看看我前面的文章《Hi3861的SAMGR--系統(tǒng)服務(wù)框架子系統(tǒng)-3》,但注意還是會(huì)有一些較大的差異。
下面以不算簡(jiǎn)單,但又不復(fù)雜的wms_server進(jìn)程為例,進(jìn)行分析。
打開 //foundation/graphic/wms/BUILD.gn 文件,查看它的依賴關(guān)系,簡(jiǎn)化整理如下:

hdi_input/lite_graphic_hals,需要外圍硬件設(shè)備的支持,硬件驅(qū)動(dòng)啟動(dòng)的時(shí)候就會(huì)加載運(yùn)行了。
samgr和lite_ipc_adapter,都沒(méi)有__attribute __((constructor))修飾,這是兩個(gè)獨(dú)立的動(dòng)態(tài)鏈接庫(kù),裝載進(jìn)來(lái)就直接用,注意,是samgr自己而已,并不包含"samgr_server:server"和"samgr_client:client"。
Broadcast服務(wù),包含了“Provider and subscriber”feature,不過(guò)好像實(shí)際上并沒(méi)有使用到。
wms_server進(jìn)程還依賴本進(jìn)程代碼中提供的WMS/IMS服務(wù),都沒(méi)有feature。
整理的表格如下:

從上表的依賴關(guān)系來(lái)看,它就依賴一個(gè)broadcast 組件提供的Service/Feature,以及它自己wms_server組件所提供的Service:WMS/IMS,所以從實(shí)際跑起來(lái)的log可以驗(yàn)證,在main()跑起來(lái)之前,__attribute __((constructor))修飾的Servic/Feature的Init函數(shù)先跑起來(lái):

在main函數(shù)跑起來(lái)之前,wms_server進(jìn)程地址空間內(nèi),已經(jīng)有一張由本進(jìn)程的SamgrLiteImpl g_samgrImpl控制的靜態(tài)展開圖了(這里就不放展開圖了,可以參考《Hi3861的SAMGR--系統(tǒng)服務(wù)框架子系統(tǒng)-2》的展開圖進(jìn)行理解)。
main( )中,跑完HiFbdevInit()/InitDriver()后,會(huì)通過(guò)HOS_SystemInit()來(lái)調(diào)用SAMGR_Bootstrap()函數(shù),為上面三個(gè)service:Broadcast/WMS/IMS 創(chuàng)建各自的 TaskPool、Task、Queue,其中WMS/IMS是同級(jí)別的SHARED_TASK,所以它們共用一個(gè)Task/Queue,在收發(fā)消息時(shí)將會(huì)通過(guò)ServiceID來(lái)做區(qū)分。Task運(yùn)行起來(lái)之后,立即監(jiān)聽自己的消息隊(duì)列,處理消息。

三個(gè)service:Broadcast/WMS/IMS的消息隊(duì)列,各自會(huì)首先收到一個(gè)MSG_DIRECT消息,由HandleInitRequest()來(lái)處理,這個(gè)HandleInitRequest() 內(nèi),會(huì)調(diào)用DEFAULT_Initialize(serviceImpl)來(lái)初始化Service/Feature。
DEFAULT_Initialize(serviceImpl) 函數(shù)內(nèi)的行為,對(duì)于輕量系統(tǒng)來(lái)說(shuō),就是調(diào)用Service/Feature的生命周期函數(shù)Initialize()/OnInitialize()來(lái)完成初始化工作,就OK了,SAMGR_RegisterServiceApi() 函數(shù)是空的樁函數(shù)。但是對(duì)于小型系統(tǒng)來(lái)說(shuō),SAMGR_RegisterServiceApi()有另外的實(shí)現(xiàn),它是進(jìn)入一個(gè)新世界的入口,這里先點(diǎn)到為止,后面我們會(huì)詳細(xì)講。
至此,系統(tǒng)服務(wù)進(jìn)程wms_server就可以開始工作了。
“[wms.cpp] main[5-4]: GetInstance()->Run()”這一步,InputManagerService instance對(duì)象就開始無(wú)休止地監(jiān)測(cè)按鍵/屏幕觸控等輸入性質(zhì)的事件,并做出響應(yīng)。
“[wms.cpp] main[5-5]: while(1)”這一步,也通過(guò)“OHOS::LiteWM::GetInstance()->MainTaskHandler();”開始無(wú)休止地根據(jù)需要重繪窗口顯示內(nèi)容。
其他五個(gè)進(jìn)程,啟動(dòng)情況類似,或更簡(jiǎn)單一些,或更復(fù)雜一些,但都會(huì)跑類似的流程,各個(gè)進(jìn)程內(nèi)部,都由自己的SamgrLiteImpl g_samgrImpl來(lái)管理本進(jìn)程內(nèi)的Service/Feature,進(jìn)程內(nèi)部的Service線程,直接通過(guò)消息隊(duì)列機(jī)制來(lái)進(jìn)行通信即可,要想跨進(jìn)程進(jìn)行交互,那就需要更復(fù)雜的機(jī)制了。
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)