Hi3861的SAMGR--系統服務框架子系統-1
1. 初步了解
先看README文檔,位于LTS/foundation/distributedschedule/samgr_lite/README_zh.md。
我們對其中的部分內容先做一下初步的理解。
系統服務框架[system ability (SA) framework],是為了屏蔽不同的硬件架構、不同的平臺資源、不同的運行形態等軟硬件差異,而提供的統一的系統服務開發框架。
根據處理器的不同架構,如RISC-V架構(基于精簡指令集RISC的開源架構)、ARM架構(如ARM的Cortex-M/Cortex-A等)、x86架構(主要用于PC市場,目前鴻蒙暫不支持,但指不定哪天就宣布支持了)等,目前分為兩類硬件平臺,以下簡稱M核(平臺)、A核(平臺)。
- M核:處理器架構為Cortex-M或同等處理能力的硬件平臺,系統內存一般低于512KB,無文件系統或者僅提供一個可有限使用的輕量級文件系統,遵循CMSIS接口規范。
- A核:處理器架構為Cortex-A或同等處理能力的硬件平臺,內存資源大于512KB,文件系統完善,可存儲大量數據,遵循POSIX接口規范。
系統服務框架基于面向服務的架構(SOA,Service-Oriented Architecture),提供了服務(service)開發、服務的子功能(feature)開發、對外接口(IUnknown)的開發、以及多服務共進程、進程間服務調用等開發能力。其中:
- M核:包含服務開發、服務的子功能開發、對外接口的開發以及多服務共進程的開發框架。
- A核:在M核能力基礎之上,包含了進程間服務調用、進程間服務調用權限控制、進程間服務接口的開發等能力。
依賴關系上:
- M核:系統依賴bootstrap服務,在系統啟動函數中調用HOS_SystemInit()函數。
- A核:系統依賴samgr庫,在main函數中調用SAMGR_Bootstrap()函數。
我的簡單理解:
- samgr是一個系統服務開發框架,開發者可以根據這里規定的規則,開發自定義的服務和功能(service+feature)、接口等等。
示例程序在Hi3861/applications/sample/wifi-iot/app/samgr/,打開BUILD.gn的編譯規則即可參與編譯。
示例程序可能會有編譯錯誤,可以獲取gitee上的最新代碼對比著進行修改,或者參考《WiFi IoT 編譯samgr模塊》 進行修改。
編譯出來的程序可能會出現kernel panic,我估計很大的原因是一次性注冊和啟動的service/feature/task太多了,導致系統資源耗盡引起的,所以最好還是只編譯部分需要驗證的示例程序,不要一次全部編譯完。我后面附上的log,就是只編譯了service_example.c和feature_example.c抓取的。
- samgr提供了對所有service、feature、接口的統一管理,包含了跨設備的service/feature的管理和調度,這是鴻蒙系統非常核心的特性之一。
2. 代碼目錄結構
先看一下LTS/foundation/distributedschedule/samgr_lite/ 的代碼結構:
看上去相當復雜。
再看對應的Hi3861/foundation/distributedschedule/ 代碼結構:
兩相對比,其實大致上是一樣的。
去 Hi3861/foundation/distributedschedule/service/samgr_lite/ 目錄下看BUILD.gn文件的構建規則,把只在A核上編譯的部分灰化,如上表,剩下的基本上就是M核要用到的了。
本文先只從Hi3861工程的角度來看samgr子系統,所以代碼基本上只需要看:
- Hi3861/foundation/distributedschedule/service/samgr_lite/communication/broadcast/
- Hi3861/foundation/distributedschedule/service/samgr_lite/samgr/source/
因為samgr“依賴bootstrap服務”,所以連帶也要看 Hi3861/base/startup/services/bootstrap_lite/ 的代碼。
至于:
- Hi3861/foundation/distributedschedule/service/samgr_lite/samgr/adapter/
這是對調用者屏蔽了平臺差異性的統一接口的聲明和實現,暫不進一步深究。
- Hi3861/foundation/distributedschedule/service/samgr_lite/samgr/registry/
這里定義了三個弱引用的API:
- SAMGR_RegisterServiceApi()
- SAMGR_FindServiceApi()
- SAMGR_RegisterFactory()
它們在/samgr_server/source/ samgr_server.c 中有實現,估計和跨設備的服務調用有關,但是M核不編譯samgr_server,所以,M核的上述三個API其實沒做什么工作,這里也暫不進一步深究。
這樣清理一下相關代碼和模塊關系就會發現簡單很多,入手也會相對容易一些,下面我們就開始“Read the f**king source code :)”。
3. 大概流程
Hi3861平臺在啟動到HOS_SystemInit()時,
- void HOS_SystemInit(void)
- {
- ......
- printf("[system_init] [7-4]: SYS_INIT(service)=====================\n");
- SYS_INIT(service);
- printf("[system_init] [7-5]: SYS_INIT(feature)=====================\n");
- SYS_INIT(feature);
- ......
- printf("[system_init] [7-7]: SAMGR_Bootstrap()=====================\n");
- SAMGR_Bootstrap();
- }
會分別通過上面三步來:向samgr注冊系統服務(service)、注冊系統服務提供的功能(feature)、通過samgr啟動并開始管理系統服務和功能。
從抓回來的log看:
- [system_init] [7-4]: SYS_INIT(service)=====================
- [bootstrap_service] SYS_SERVICE_INIT(Init): Bootstrap
- [samgr_lite] SAMGR_GetInstance(mutex=NULL): NO SAMGR instance, Init() to create ONE
- [samgr_lite] Init. g_samgrImpl
- [samgr_lite] Init. mutex[956036]. sharedPool[0-8] reset to 0. status=0[BOOT_SYS]
- [samgr_lite] SAMGR_GetInstance(mutex=956036)
- [samgr_lite] RegisterService(Name:Bootstrap)->Sid[0]
- [broadcast_service] SYS_SERVICE_INIT(Init): Broadcast
- [samgr_lite] RegisterService(Name:Broadcast)->Sid[1]
- [hiview_service] SYS_SERVICE_INIT(Init): hiview
- [samgr_lite] RegisterService(Name:hiview)->Sid[2]
- [samgr_lite] RegisterFeatureApi(serviceName[hiview], feature[(null)])
- [hiview_service] Init.InitHiviewComponent.
- [system_init] [7-5]: SYS_INIT(feature)=====================
- [pub_sub_feature] Init. SYS_FEATURE_INIT(Init) g_broadcastFeature: Provider and subscriber
- [samgr_lite] RegisterFeature(serviceName:Broadcast, featureName:Provider and subscriber)->Fid[0]
- [pub_sub_implement] BCE_CreateInstance: set g_pubSubImplement.feature = &g_broadcastFeature
- [samgr_lite] RegisterFeatureApi(serviceName[Broadcast], feature[Provider and subscriber])
會注冊三個系統服務和一個系統feature。
第一個注冊的系統服務是Bootstrap,這個時候samgr還沒有實例,所以需要先初始化samgr的全局實例g_samgrImpl,然后才能通過RegisterService((Service *)&bootstrap)來向g_samgrImpl注冊bootstrap服務。這時候g_samgrImpl會通過SAMGR_CreateServiceImpl()來為bootstrap創建一個ServiceImpl 對象,將該對象加入g_samgrImpl.services向量中,并返回它在向量中的位置[0],以此作為bootstrap 的ServiceID[0](文中或log中簡寫為Sid,同樣FeatureID簡寫為Fid,QueueID簡寫為Qid)。
接下來注冊的第二個服務broadcast和第三個服務hiview,就可以直接通過RegisterService((Service *)Xxx)記錄進g_samgrImpl.services向量里了,Sid分別是[1]/[2]。
接下來再注冊broadcast service的feature:PUB_SUB_FEATURE。feature的注冊和運行需要依賴于對應的service,一個service可以有0個、1個或多個feature。通過RegisterFeature(service, feature)的調用,samgr也會先生成一個FeatureImpl對象,再將該對象加入到 g_samgrImpl.services向量中對應的service 的ServiceImpl 對象的向量features中去,以完成feature的注冊。這一句看起來比較繞,簡單來說,就是g_samgrImpl的services向量管理著所有登記在冊的services的ServiceImpl ,而每個ServiceImpl又通過自己的features向量管理自己所有的features。【更具體的實現過程,后面會有詳細的代碼分析。】
在接下來的系統運行中,serviceName/serviceID(Sid) 和featureName/featureID(Fid) 都是非常重要的信息,samgr可以通過它們來找到對應的ServiceImpl/FeatureImpl對象,并提供相應的服務/功能。
- [system_init] [7-7]: SAMGR_Bootstrap()=====================
- [samgr_lite] SAMGR_Bootstrap. Begin: size=3
- InitializeAllServices: size=3
- Add service: Bootstrap to TaskPool: 0x0...
- TaskPool: 0xfa448...
- Qid: 956360...
- Add service: Broadcast to TaskPool: 0x0...
- TaskPool: 0xfaab8...
- Qid: 956404...
- Add service: hiview to TaskPool: 0x0...
- TaskPool: 0xfac78...
- Qid: 956448...
- [task_manager] SAMGR_StartTaskPool:
- CreateTask[Bootstrap(Tid: 0xe8780), size(8192), Prio(25)]-OK!
- [task_manager] SAMGR_StartTaskPool:
- CreateTask[Broadcast(Tid: 0xe871c), size(4096), Prio(32)]-OK!
- [task_manager] SAMGR_StartTaskPool:
- CreateTask[hiview(Tid: 0xe87e4), size(2048), Prio(24)]-OK!
- [samgr_lite] SAMGR_Bootstrap. End.
這里就是samgr開始為各個登記在g_samgrImpl.services向量里的service創建Queue和TaskPool這些運行環境了,在SAMGR_StartTaskPool() 這一步依次創建和啟動service任務/線程,線程入口是TaskEntry()函數,位于Hi3861/foundation/distributedschedule/services/samgr_lite/samgr/source/task_manager.c 文件內。
各個服務的TaskEntry線程,監控著各自的消息隊列Queue,從中檢出消息,獲取Exchange封裝的數據,根據里面的相關標記調用相關的msg handler來進行對應的處理。
上面的流程僅僅是啟動了用SYS_SERVICE_INIT()和SYS_FEATURE_INIT() 標記的service和feature,而通過SYSEX_SERVICE_INIT/APP_SERVICE_INIT/ SYSEX_FEATURE_INIT/APP_FEATURE_INIT 標記的service和feature(如在前面提到的示例程序samgr里定義的一部分service和feature),則會在系統啟動到 BOOT_APP 這一步時,通過發送消息BOOT_SYS_COMPLETED到Bootstrap的消息隊列中,讓Bootstrap調用MessageHandle()來處理該消息:通過調用INIT_APP_CALL(service)和INIT_APP_CALL(feature)來完成APP service和Feature的啟動,從而提供用戶定義的服務和功能。
上面是service/feature的注冊和啟動的大概過程,主要的工作都是samgr來實現的,這就是samgr_lite組件的基礎代碼部分所提供的功能。
log和簡單的步驟描述,見附件log。
接下來我會對一些重要的結構體進行分解,對部分流程進行詳細的分析。