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

在對“LAYER_INITCALL”這個宏的展開上,輕量系統(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" ]
- }
- }
也就是說輕量系統(tǒng)沒有定義"LAYER_INIT_SHARED_LIB",而小型系統(tǒng)則是包含這個宏的定義的,為什么要將"LAYER_INIT_SHARED_LIB"的定義要放在samgr_lite/samgr組件上,這個稍后會講到。
輕量系統(tǒng):
輕量系統(tǒng)上,LAYER_INITCALL使用__attribute __((section(“section_name”)))來展開, 其作用是在編譯階段,將函數(shù)或數(shù)據(jù)鏈接到指定的名為"section_name"對應(yīng)的段中。在系統(tǒng)啟動時(shí),再通過MODULE_INIT/SYS_INIT宏引導(dǎo)去"section_name"對應(yīng)的段中找到記錄的入口函數(shù),并依次執(zhí)行它們。
注意,這種啟動方式是串行的,前一個服務(wù)的入口函數(shù)沒有執(zhí)行完,并不會執(zhí)行后一個服務(wù)的入口函數(shù),這就是不能在SYS_SERVICE_INIT /SYS_FEATURE_INIT等宏標(biāo)記的入口函數(shù)做太多事情、特別是不能做阻塞式的事情的原因。
更具體的啟動細(xì)節(jié),請去《Hi3861_WiFiIoT工程的一點(diǎn)理解》進(jìn)行閱讀理解。
小型系統(tǒng):
小型系統(tǒng)上,LAYER_INITCALL使用__attribute __((constructor))來展開,對應(yīng)還有一個__attribute __((destructor)),它們就類似于C++的類中的構(gòu)造函數(shù)和析構(gòu)函數(shù)的作用。
- 如果函數(shù)被設(shè)定為constructor屬性,則該函數(shù)會在main()函數(shù)開始執(zhí)行之前被自動地先執(zhí)行;
- 如果函數(shù)被設(shè)定為destructor屬性,則該函數(shù)會在main()函數(shù)執(zhí)行結(jié)束之后或者exit()被調(diào)用后,被自動地執(zhí)行。
這在小型系統(tǒng)中非常有用,比如某個進(jìn)程的運(yùn)行依賴ServiceA和FeatureAa,ServiceA和FeatureAa的Init函數(shù)都用SYS_SERVICE_INIT /SYS_FEATURE_INIT標(biāo)記了,那在這個進(jìn)程啟動時(shí)的main函數(shù)執(zhí)行之前,ServiceA和FeatureAa的Init函數(shù)就會先于main被執(zhí)行。所以,小型系統(tǒng)中,梳理清楚關(guān)鍵進(jìn)程的服務(wù)依賴關(guān)系就顯得非常重要了。
下面我們就進(jìn)入正題,小型系統(tǒng)的系統(tǒng)服務(wù)的整體的啟動流程。
我們知道,鴻蒙系統(tǒng)從內(nèi)核態(tài)切換到用戶態(tài),跑的第一個進(jìn)程Init,也叫用戶態(tài)根進(jìn)程,它讀取并分析/etc/init.cfg配置文件(//vendor/hisilicon/hispark_taurus/init_configs/init_liteos_a_3516dv300.cfg的副本),根據(jù)上面的記錄,按順序啟動幾個關(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)啟動的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ù)跑起來,而在這之前,又需要先去跑完它依賴的所有的“ServiceA和FeatureAa”的__attribute __((constructor))函數(shù),然后main()的最后一步,一般是進(jìn)入while (1) { pause() }狀態(tài),也就是服務(wù)進(jìn)程進(jìn)入后臺,默默守護(hù)著本進(jìn)程以及它的所有子進(jìn)程/子線程,有點(diǎn)像蜂王/蟻后一樣,進(jìn)程對內(nèi)/外提供的服務(wù)、功能、接口等具體工作,由它的子子孫孫來完成。
上面提到,一個服務(wù)進(jìn)程對別人的依賴關(guān)系非常重要,下表是我對上面init OK的9個進(jìn)程的依賴關(guān)系所做的一些梳理,把每一個進(jìn)程的依賴關(guān)系一層層找到列了出來,從上到下,把對三方庫的依賴、重復(fù)出現(xiàn)的依賴,都灰化掉了,這樣看起來就清爽多了?!久看沃叵凑矶及l(fā)現(xiàn)會有一些小小的疏漏,所以這個表格還不算完美】

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

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

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

在main函數(shù)跑起來之前,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()后,會通過HOS_SystemInit()來調(diào)用SAMGR_Bootstrap()函數(shù),為上面三個service:Broadcast/WMS/IMS 創(chuàng)建各自的 TaskPool、Task、Queue,其中WMS/IMS是同級別的SHARED_TASK,所以它們共用一個Task/Queue,在收發(fā)消息時(shí)將會通過ServiceID來做區(qū)分。Task運(yùn)行起來之后,立即監(jiān)聽自己的消息隊(duì)列,處理消息。

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