Hi3516的SAMGR--系統服務框架子系統-9-samgr EP的注冊
接下來我們看一下管理者g_server(包含samgr EP)的啟動和對外提供服務的過程。
而foundation進程作為一個client,向管理者g_server注冊的過程,與前文《系統服務框架子系統-8-client EP的注冊》的完全一致,只是service和feature多了很多。
這次我們在分析流程的同時,對著log來驗證(log文件也在前文-8附件中),由于任務調度的原因,log會有點交叉,稍顯混亂,但同一個service/feature的log,在時間線上的先后順序是沒問題的,可以通過關鍵字搜索過濾出來。
SamgrServer g_server 在samgr_server.c文件內,是全局唯一的管理者服務對象,foundation進程依賴的一大堆service和feature中就包括了它,foundation進程跑main之前,先跑完它所依賴的所有service和feature的Init,跑到samgr_server.c的SYS_SERVICE_INIT(InitializeRegistry)時:

可以將其粗略分成4部分:
[4-1] SASTORA_Init(&g_server.store) 這是一個鏈表+向量的結構,后面詳細講,暫時也沒打印log。
[4-2] g_server.samgr = SAMGR_CreateEndpoint("samgr", RegisterSamgrEndpoint),為g_server創建一個EP,因為這個EP很特殊,就是知名EP,要放在這里來創建,但還沒開始“向自己注冊自己”。
[4-3] RegisterService((Service *)&g_server),向本進程(foundation)的g_samgrImpl 注冊服務。
[4-4] 創建Vector sysCapabilitys,調用ParseSysCap()來讀取和分析“/etc/system_capability.json”文件,將系統的Capabilitys,按格式添加到Vector sysCapabilitys中去。“/etc/system_capability.json”文件是“//foundation/distributedschedule/samgr_lite/config/system_capability.json”文件的副本。
跑的log如下:

接下來就是等foundation進程跑main()函數,調用SAMGR_Bootstrap()去為它依賴的所有service(包括samgr)創建線程和消息隊列:

在foundation依賴的所有service中(甚至整個用戶態下的所有線程中),只有samgr線程的任務優先級別是PRI_BUTT-1 = 38這個級別的:
- TaskConfig config = {LEVEL_HIGH, PRI_BUTT - 1, 0x400, 20, SINGLE_TASK};
看看PRI_BUTT的定義就知道了,通信相關的線程(即各個EP中的boss線程),優先級都已經PRI_ABOVE_NORMAL了,而samgr是通信的關鍵節點,它的優先級更高,都已經接近“Upper limit of the priority”,這也反映出通信效率在鴻蒙系統中至高的地位。

前文“線程/進程間通信模型”中說到的線程只有0到31個級別,數字越小,優先級別越高,這里怎么有超過31的級別,并且數字越大,優先級別越高呢?

“SAMGR_LINUX_ADAPTER”定義在 //foundation/distributedschedule/samgr_lite/samgr/adapter/BUILD.gn :
- if (ohos_kernel_type == "linux") {
- defines += [ "SAMGR_LINUX_ADAPTER" ]
- }
原來上面定義的TaskPriority是用Linux內核的標準系統所使用的線程優先級別定義,而用LiteOS_A內核的小型系統,則會做一次轉換,使用0到31這種級別來表示線程優先級,經過這樣的轉換,小型系統中的samgr的線程優先級是1,仍然是非常高級別的(更高級別的0級,可能是內核的什么線程,我沒再往下深挖了)。
所以,samgr服務的task被創建出來之后,會優先得到系統的調度,去跑它的初始化,也就是要去跑DEFAULT_Initialize()的流程了:

四步,因為“NO Feature”,所以只跑前兩步,但是第1步跑的samgr service的 Initialize() 函數有點特別:

它比別的service的Initialize()函數多跑了一個SAMGR_AddRouter(......,GET_IUNKNOWN(*server)),需要特別注意第四個參數:GET_IUNKNOWN(*server),這個參數可以保證proxy符合要求,確保這個router能夠正確添加到管理者g_server->samgr這個EP的Vector routers里面去。
SAMGR_AddRouter()里面經過確保條件滿足,將router添加到Vector routers里面去之后就Listen(endpoint),這是知名EP的第一個(也是唯一的一個)router,所以會創建一個boss線程,然后跑Receive()入口。因為線程調度的原因,Receive()的流程稍晚一點點去跑,也是內外兩層while循環,但是因為內層執行的registerEP函數指針指向的是RegisterSamgrEndpoint(),也就是samgr EP向自己注冊自己,所以非常快就OK了:

這個時候,g_server的知名EP,是這個樣子的:

因為是知名EP,且沒有Feature,Receive()的第3步也跳過,直接就StartLoop了,這就開始接收早于它的其他EP(ipc client)的IPC注冊消息了,由Dispatch()函數進行下一步處理(后面會進一步分析),所以接下來的log中,你可以看到:

先前先跑起來向知名EP注冊自己的client EP,經過若干次的 retry之后,終于注冊上了,成功拿到了自己的handle。
回到samgr的DEFAULT_Initialize()流程第二步:
- DEFAULT_Initialize_samgr->RegServiceApi(ServiceImpl->defaultApi[0])
實際調用的是:
- SAMGR_RegisterServiceApi(......,ServiceImpl->defaultApi)
這里的defaultApi是 NULL 的,原因與前文中Broadcast服務的defaultApi為NULL是一樣的。
三步流程中,第1步,初始化了foundation進程自己的g_remoteRegister,也為它創建了client EP,這個EP就是普通的client EP,也就是foundation進程自己對外進行IPC的通信終端,與上面的雖然也同在foundation進程內的server EP,是不一樣的,看前文《線程/進程間通信模型》的圖就明白了。
三步流程中,第2步,因為defaultApi是 NULL 的,會添加router失敗,也就不會為client EP創建boss線程了,需要等后面的service成功添加第一個router的時候,才會創建boss線程。
接下來就是foundation進程的其它service,通過各自的消息隊列收到Init消息,通過
- [samgr_lite] HandleInitRequest: Initing_Service......
來跑各自的DEFAULT_Initialize()流程了,與client EP的注冊流程完全一致,只不過是這個進程的service/feature很多,經過系統的調度之后,打印出來的log會有一些交叉,分析起來會有一點雜亂,不過通過搜索關鍵字來過濾一下,流程也是很清晰可證的。