微吼云上線多路互動直播服務 加速多場景互動直播落地
831
2025-04-04
移植案例與原理 - startup子系統之bootstrap_lite服務啟動引導部件
bootstrap_lite服務啟動引導組件提供了各服務和功能的啟動入口標識。在SAMGR(System ability manager,系統服務管理)啟動時,會調用bootstrap_lite標識的入口函數,并啟動系統服務。本文介紹下移植開發板時如何適配服務啟動引導部件bootstrap_lite,并介紹下相關的運行機制原理。bootstrap_lite啟動引導部件定義在build\lite\components\startup.json。bootstrap_lite啟動引導部件源代碼目錄如下:
base/startup/bootstrap_lite/ # 啟動引導組件 └── services └── source # 啟動引導組件源文件目錄
1、bootstrap_lite服務啟動引導部件適配示例
1.1 產品解決方案配置啟用部件
移植開發板適配startup子系統之bootstrap_lite服務啟動引導部件時,需要在產品解決方案的config.json增加下述配置項,可以參考vendor\bestechnic\display_demo\config.json中的配置示例:
{ "subsystem": "startup", "components": [ { "component": "bootstrap_lite" }, ...... ] },
1.2 使用bootstrap服務啟動部件提供的初始化宏函數
然后就可以使用bootstrap服務啟動部件提供的初始化宏函數SYS_SERVICE_INIT、APP_SERVICE_INIT等來自動初始化服務,示例代碼可以參考device\board\fnlink\v200zr\liteos_m\at\at_wifi.c中的用法,片段如下,可以看到調用了宏函數來初始化RegisterCustomATCmd函數實現的服務。device\board\bearpi\bearpi_hm_nano\app\目錄下有更多的使用示例。下文分析實現機制原理。
static void RegisterCustomATCmd() { cmd_tbl_t cmd_list[] = { {"AT+IFCFG", 8, at_lwip_ifconfig, "AT+IFCFG - ifconfig\n"}, {"AT+STARTAP", 7, at_start_softap, "AT+STARTAP - start wifi softap\n"}, {"AT+STOPAP", 1, at_stop_softap, "AT+STOPAP - stop wifi softap\n"}, {"AT+STARTSTA", 1, at_start_wifista, "AT+STARTSTA - start wifi sta\n"}, {"AT+STOPSTA", 1, at_stop_wifista, "AT+STOPSTA - stop wifi sta\n"}, {"AT+DHCP", 3, at_setup_dhcp, "AT+DHCP - dhcp\n"}, {"AT+DHCPS", 3, at_setup_dhcps, "AT+DHCPS - dhcps\n"}, }; for (int i = 0; i < sizeof(cmd_list) / sizeof(cmd_tbl_t); i++) { console_cmd_add(&cmd_list[i]); } } SYS_SERVICE_INIT(RegisterCustomATCmd);
1.3 鏈接腳本中增加zInit代碼段
適配bootstrap_lite部件時,還需要在鏈接腳本文件中手動新增如下段,鏈接腳本示例可以參考//device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/out/best2600w_liteos/_best2001.lds,還可以參考device\soc\hisilicon\hi3861v100\sdk_liteos\build\link\link.ld.S。從鏈接腳本片段中可以看出,有.zinitcall.bsp、.zinitcall.device、.zinitcall.core、.zinitcall.sys.service、.zinitcall.sys.feature、.zinitcall.run、.zinitcall.app.service、.zinitcall.app.feature、.zinitcall.test和.zinitcall.exit等幾種類型的段。
/* zInit code and data - will be freed after init */ .zInit (.) : { __zinitcall_bsp_start = .; KEEP (*(.zinitcall.bsp0.init)) KEEP (*(.zinitcall.bsp1.init)) KEEP (*(.zinitcall.bsp2.init)) KEEP (*(.zinitcall.bsp3.init)) KEEP (*(.zinitcall.bsp4.init)) __zinitcall_bsp_end = .; . = ALIGN(4); __zinitcall_device_start = .; KEEP (*(.zinitcall.device0.init)) KEEP (*(.zinitcall.device1.init)) KEEP (*(.zinitcall.device2.init)) KEEP (*(.zinitcall.device3.init)) KEEP (*(.zinitcall.device4.init)) __zinitcall_device_end = .; . = ALIGN(4); __zinitcall_core_start = .; KEEP (*(.zinitcall.core0.init)) KEEP (*(.zinitcall.core1.init)) KEEP (*(.zinitcall.core2.init)) KEEP (*(.zinitcall.core3.init)) KEEP (*(.zinitcall.core4.init)) __zinitcall_core_end = .; . = ALIGN(4); __zinitcall_sys_service_start = .; KEEP (*(.zinitcall.sys.service0.init)) KEEP (*(.zinitcall.sys.service1.init)) KEEP (*(.zinitcall.sys.service2.init)) KEEP (*(.zinitcall.sys.service3.init)) KEEP (*(.zinitcall.sys.service4.init)) __zinitcall_sys_service_end = .; . = ALIGN(4); __zinitcall_sys_feature_start = .; KEEP (*(.zinitcall.sys.feature0.init)) KEEP (*(.zinitcall.sys.feature1.init)) KEEP (*(.zinitcall.sys.feature2.init)) KEEP (*(.zinitcall.sys.feature3.init)) KEEP (*(.zinitcall.sys.feature4.init)) __zinitcall_sys_feature_end = .; . = ALIGN(4); __zinitcall_run_start = .; KEEP (*(.zinitcall.run0.init)) KEEP (*(.zinitcall.run1.init)) KEEP (*(.zinitcall.run2.init)) KEEP (*(.zinitcall.run3.init)) KEEP (*(.zinitcall.run4.init)) __zinitcall_run_end = .; . = ALIGN(4); __zinitcall_app_service_start = .; KEEP (*(.zinitcall.app.service0.init)) KEEP (*(.zinitcall.app.service1.init)) KEEP (*(.zinitcall.app.service2.init)) KEEP (*(.zinitcall.app.service3.init)) KEEP (*(.zinitcall.app.service4.init)) __zinitcall_app_service_end = .; . = ALIGN(4); __zinitcall_app_feature_start = .; KEEP (*(.zinitcall.app.feature0.init)) KEEP (*(.zinitcall.app.feature1.init)) KEEP (*(.zinitcall.app.feature2.init)) KEEP (*(.zinitcall.app.feature3.init)) KEEP (*(.zinitcall.app.feature4.init)) __zinitcall_app_feature_end = .; . = ALIGN(4); __zinitcall_test_start = .; KEEP (*(.zinitcall.test0.init)) KEEP (*(.zinitcall.test1.init)) KEEP (*(.zinitcall.test2.init)) KEEP (*(.zinitcall.test3.init)) KEEP (*(.zinitcall.test4.init)) __zinitcall_test_end = .; . = ALIGN(4); __zinitcall_exit_start = .; KEEP (*(.zinitcall.exit0.init)) KEEP (*(.zinitcall.exit1.init)) KEEP (*(.zinitcall.exit2.init)) KEEP (*(.zinitcall.exit3.init)) KEEP (*(.zinitcall.exit4.init)) __zinitcall_exit_end = .; . = ALIGN(4); } > FLASH
1.4 配置編譯時鏈接bootstrap庫
另外,bootstrap_lite部件會編譯//base/startup/bootstrap_lite/services/source/bootstrap_service.c,該文件中,通過SYS_SERVICE_INIT將Init函數符號指定到__zinitcall_sys_service_start和__zinitcall_sys_service_end段中,由于沒有顯式調用Init函數,所以需要將它強制鏈接到最終的鏡像。可以參考device\board\goodix\gr5515_sk\liteos_m\config.gni文件中的鏈接選項。恒玄的開發板適配時,是配置到vendor\bestechnic\display_demo\config.json文件中的自己定義的配置項force_link_libs里,該配置項在device\soc\bestechnic\bes2600\BUILD.gn中被解析、鏈接。
board_ld_flags = [ .... "-lbootstrap",
1.5 調用OHOS_SystemInit接口
函數void OHOS_SystemInit(void)定義在文件base\startup\bootstrap_lite\services\source\system_init.c中,在移植適配時,需要調用該接口。可以參考文件device\soc\bestechnic\bes2600\liteos_m\sdk\bsp\rtos\liteos\liteos_m\board.c中的使用示例。
int main(void); extern void OHOS_SystemInit(void); ...... OHOS_SystemInit(); ...... while (1) { osDelay(1000); TRACE(0, "main idle"); } }
2、bootstrap_lite服務啟動引導部件實現原理之system_init
bootstrap_lite服務啟動部件實現了服務的自動初始化,即服務的初始化函數無需顯式調用,它是使用宏定義的方式申明,在系統啟動時自動被執行。實現原理是將服務啟動的函數通過宏申明之后,放在預定義好的zInit代碼段中,系統啟動的時候調用OHOS_SystemInit接口,遍歷該代碼段并調用其中的函數。因此在適配移植時,需要在device/soc/下面具體的芯片的鏈接腳本中添加zInit段,并且在main函數里調用OHOS_SystemInit接口。
2.1 bootstrap_lite服務啟動引導部件的初始化宏
bootstrap_lite服務啟動引導部件的初始化宏定義在文件utils\native\lite\include\ohos_init.h,片段如下。初始化函數宏SYS_SERVICE_INIT(func)用于標識核心系統服務的初始化入口,該宏識別的函數在啟動過程中核心系統服務優先級2階段被調用;初始化宏SYS_SERVICE_INIT_PRI(func, priority)可以指定優先級數值,優先級的取值范圍為[0,5),調用順序為0, 1, 2, 3, 4。
/** * @brief Identifies the entry for initializing and starting a core system service by the * priority 2. * * This macro is used to identify the entry called at the priority 2 in the core system * service phase of the startup process. \n * * @param func Indicates the entry function for initializing and starting a core system service. * The type is void (*)(void). */ #define SYS_SERVICE_INIT(func) LAYER_INITCALL_DEF(func, sys_service, "sys.service") /** * @brief Identifies the entry for initializing and starting a core system service by the * specified priority. * * This macro is used to identify the entry called at the specified priority in the core system * service phase of the startup process. \n * * @param func Indicates the entry function for initializing and starting a core system service. * The type is void (*)(void). * @param priority Indicates the calling priority when starting the core system service in the * startup phase. The value range is [0,5), and the calling sequence is 0, 1, 2, 3, and 4. */ #define SYS_SERVICE_INIT_PRI(func, priority) LAYER_INITCALL(func, sys_service, "sys.service", priority)
更多的初始化宏見下文的列表,處理這些初始化宏,還有可以指定優先級的版本XXX_PRI。
2.2 LAYER_INITCALL宏定義
從上文已知,bootstrap_lite服務啟動引導部件的初始化宏會調用LAYER_INITCALL_DEF和LAYER_INITCALL宏。這些宏的定義在文件utils\native\lite\include\ohos_init.h,代碼片段如下。⑴處聲明函數類型,無參無返回值。⑵處處理定義分層初始化共享庫宏LAYER_INIT_SHARED_LIB的情況,如果沒有定義該宏,則執行⑹。在文件foundation/distributedschedule/samgr_lite/samgr/BUILD.gn中定義了該宏,在移植適配芯片開發板時,沒有定義這個宏。⑶處定義5個分層初始化級別,⑷處定義7個構建值(constructor value,簡稱CTOR Value)。⑸處是宏LAYER_INITCALL的定義,該宏需要4個參數,分別是初始化服務或功能函數func;layer是分層名稱,支持的取值為device、core、sys_service、sys_feature、app_service、app_feature和run,拼裝為CTOR_VALUE_XXX;clayer參數在定義宏LAYER_INIT_SHARED_LIB時未使用;priority是優先級參數。attribute((constructor))表示這段代碼將在main函數前調用。當傳入參數為(myFunc, sys_feature, “sys.feature”, 2)時,函數宏替換為:static __attribute__((constructor(130 + 2))) void BOOT_sys_featurer2myFunc {myFunc();}。等于定義個一個新的啟動引導函數BOOT_sys_featurer2myFunc()。
當沒有定義LAYER_INIT_SHARED_LIB宏時,執行⑹,當傳入參數為(myFunc, sys_feature, “sys.feature”, 2)時,函數宏替換為:static const InitCall __attribute__((used)) __zinitcall_sys_feature_myFunc __attribute__((section(".zinitcall.sys.feature2.init"))) = myFunc,除了__attribute__部分,等于聲明一個函數類型InitCall的變量__zinitcall_sys_feature_myFunc。該函數變量放入section段".zinitcall.sys.feature2.init"內,所以移植適配時,需要在芯片開發板的鏈接腳本里添加zInit代碼段。
⑴ typedef void (*InitCall)(void); #define USED_ATTR __attribute__((used)) ⑵ #ifdef LAYER_INIT_SHARED_LIB ⑶ #define LAYER_INIT_LEVEL_0 0 #define LAYER_INIT_LEVEL_1 1 #define LAYER_INIT_LEVEL_2 2 #define LAYER_INIT_LEVEL_3 3 #define LAYER_INIT_LEVEL_4 4 ⑷ #define CTOR_VALUE_device 100 #define CTOR_VALUE_core 110 #define CTOR_VALUE_sys_service 120 #define CTOR_VALUE_sys_feature 130 #define CTOR_VALUE_app_service 140 #define CTOR_VALUE_app_feature 150 #define CTOR_VALUE_run 700 ⑸ #define LAYER_INITCALL(func, layer, clayer, priority) \ static __attribute__((constructor(CTOR_VALUE_##layer + LAYER_INIT_LEVEL_##priority))) \ void BOOT_##layer##priority##func() {func();} #else ⑹ #define LAYER_INITCALL(func, layer, clayer, priority) \ static const InitCall USED_ATTR __zinitcall_##layer##_##func \ __attribute__((section(".zinitcall." clayer #priority ".init"))) = func #endif // Default priority is 2, priority range is [0, 4] #define LAYER_INITCALL_DEF(func, layer, clayer) \ LAYER_INITCALL(func, layer, clayer, 2)
2.3 OHOS_SystemInit函數
函數OHOS_SystemInit()定義在文件base\startup\bootstrap_lite\services\source\system_init.c,代碼如下。調用宏函數MODULE_INIT、SYS_INIT和函數SAMGR_Bootstrap()進行初始化啟動。
void OHOS_SystemInit(void) { MODULE_INIT(bsp); MODULE_INIT(device); MODULE_INIT(core); SYS_INIT(service); SYS_INIT(feature); MODULE_INIT(run); SAMGR_Bootstrap(); }
我們詳細分析下宏函數MODULE_INIT和SYS_INIT的源代碼,這2個宏函數在文件base\startup\bootstrap_lite\services\source\core_main.h中定義,代碼如下。這些宏函數的參數大都為name和step,name取值為bsp、device、core、service、feature、run,step取值為0。從⑺和⑻處可以看出,分別調用SYS_CALL、MODULE_CALL兩個宏,第二個參數設置為0。⑸處定義的MODULE_BEGIN函數,用于返回鏈接腳本中定義的代碼段的開始地址,當傳入參數為bsp時,返回&__zinitcall_bsp_start,MODULE_BEGIN函數被展開為如下片段:
{ extern InitCall __zinitcall_sys_start; \ InitCall *initCall = &__zinitcall_bsp_start; \ (initCall); \ }
⑹處定義的MODULE_END函數,用于返回鏈接腳本中定義的代碼段的結束地址,當傳入參數為bsp時,返回&__zinitcall_bsp_end,MODULE_END函數被展開為如下片段:
{ extern InitCall __zinitcall_bsp_end; \ InitCall *initCall = &__zinitcall_bsp_end; \ (initCall); \ }
⑶和⑷處定義的SYS_BEGIN、SYS_END代碼類似,分于返回鏈接腳本中定義的標記系統服務或特性的代碼段的開始、結束地址,即&__zinitcall_sys_service_start、&__zinitcall_sys_service_end、&__zinitcall_sys_feature_start、&__zinitcall_sys_feature_end。⑴處定義的SYS_CALL函數,分別獲取鏈接腳本中zInit代碼段的開始initcall和結束地址initend,這些地址存放的是初始化函數的地址,語句 (*initcall)()會循環調用執行這些初始化函數。⑵處MODULE_CALL宏類似。
⑴ #define SYS_CALL(name, step) \ do { \ InitCall *initcall = (InitCall *)(SYS_BEGIN(name, step)); \ InitCall *initend = (InitCall *)(SYS_END(name, step)); \ for (; initcall < initend; initcall++) { \ (*initcall)(); \ } \ } while (0) ⑵ #define MODULE_CALL(name, step) \ do { \ InitCall *initcall = (InitCall *)(MODULE_BEGIN(name, step)); \ InitCall *initend = (InitCall *)(MODULE_END(name, step)); \ for (; initcall < initend; initcall++) { \ (*initcall)(); \ } \ } while (0) ...... ⑶ #define SYS_BEGIN(name, step) \ ({ extern InitCall __zinitcall_sys_##name##_start; \ InitCall *initCall = &__zinitcall_sys_##name##_start; \ (initCall); \ }) ⑷ #define SYS_END(name, step) \ ({ extern InitCall __zinitcall_sys_##name##_end; \ InitCall *initCall = &__zinitcall_sys_##name##_end; \ (initCall); \ }) ⑸ #define MODULE_BEGIN(name, step) \ ({ extern InitCall __zinitcall_##name##_start; \ InitCall *initCall = &__zinitcall_##name##_start; \ (initCall); \ }) ⑹ #define MODULE_END(name, step) \ ({ extern InitCall __zinitcall_##name##_end; \ InitCall *initCall = &__zinitcall_##name##_end; \ (initCall); \ }) ⑺ #define SYS_INIT(name) \ do { \ SYS_CALL(name, 0); \ } while (0) ⑻ #define MODULE_INIT(name) \ do { \ MODULE_CALL(name, 0); \ } while (0)
3、 bootstrap_lite服務啟動引導部件實現原理之bootstrap_service
在文件base\startup\bootstrap_lite\services\source\bootstrap_service.h中定義了2個宏函數INIT_APP_CALL和INIT_TEST_CALL,分別用來調用代碼段&__zinitcall_app_XXX_start、&__zinitcall_app_XXX_end和&__zinitcall_test_start、&__zinitcall_test_end之間的初始化啟動函數。bootstrap_service.h文件中的宏和base\startup\bootstrap_lite\services\source\core_main.h文件中的宏類似,不再一一分析。
3.1 結構體struct Bootstrap
在文件base\startup\bootstrap_lite\services\source\bootstrap_service.c中定義了結構體struct Bootstrap,如下代碼⑵處。其中結構體中的INHERIT_SERVICE定義在文件foundation/distributedschedule/samgr_lite/interfaces/kits/samgr/service.h,見代碼片段⑴處。
⑴ #define INHERIT_SERVICE \ const char *(*GetName)(Service * service); \ BOOL (*Initialize)(Service * service, Identity identity); \ BOOL (*MessageHandle)(Service * service, Request * request); \ TaskConfig (*GetTaskConfig)(Service * service) ...... ⑵ typedef struct Bootstrap { INHERIT_SERVICE; Identity identity; uint8 flag; } Bootstrap;
結構體Identity定義在文件foundation\distributedschedule\samgr_lite\interfaces\kits\samgr\message.h中,用于標識一個服務或特性。
/** * @brief Identifies a service and feature. * * You can use this structure to identity a {@link IUnknown} feature to which messages will be * sent through the asynchronous function of {@link IUnknown}. \n * */ struct Identity { /** Service ID */ int16 serviceId; /** Feature ID */ int16 featureId; /** Message queue ID */ MQueueId queueId; };
3.2 Init(void)函數
講解移植適配示例時,我們已經知道,bootstrap_lite部件會編譯//base/startup/bootstrap_lite/services/source/bootstrap_service.c,該文件通過函數宏SYS_SERVICE_INIT將Init()函數符號灌段到__zinitcall_sys_service_start和__zinitcall_sys_service_end代碼段中,代碼片段如下。下文再詳細分析GetName、Initialize、MessageHandle和GetTaskConfig函數。
static const char *GetName(Service *service); static BOOL Initialize(Service *service, Identity identity); static TaskConfig GetTaskConfig(Service *service); static BOOL MessageHandle(Service *service, Request *request); static void Init(void) { static Bootstrap bootstrap; bootstrap.GetName = GetName; bootstrap.Initialize = Initialize; bootstrap.MessageHandle = MessageHandle; bootstrap.GetTaskConfig = GetTaskConfig; bootstrap.flag = FALSE; SAMGR_GetInstance()->RegisterService((Service *)&bootstrap); } SYS_SERVICE_INIT(Init);
3.3 GetName和Initialize函數
GetName函數代碼如下,其中BOOTSTRAP_SERVICE定義在文件foundation\distributedschedule\samgr_lite\interfaces\kits\samgr\samgr_lite.h中,取值為"Bootstrap",表示啟動引導服務。
static const char *GetName(Service *service) { (void)service; return BOOTSTRAP_SERVICE; }
Initialize函數定義如下,用于設置啟動引導服務的標識信息。
static BOOL Initialize(Service *service, Identity identity) { Bootstrap *bootstrap = (Bootstrap *)service; bootstrap->identity = identity; return TRUE; }
3.4 MessageHandle函數和GetTaskConfig函數
MessageHandle函數和GetTaskConfig函數代碼如下,MessageHandle函數用于處理各種請求,請求消息編號定義request->msgId定義在文件foundation\distributedschedule\samgr_lite\interfaces\kits\samgr\samgr_lite.h中的枚舉enum BootMessage,如下⑴處所示。在MessageHandle函數中,當請求的消息編號為BOOT_SYS_COMPLETED系統服務初始化完成時,檢查應用服務是否加載。當應用沒有加載時,執行INIT_APP_CALL宏函數調用zInit代碼段上的應用服務和應用特性初始化函數。然后執行⑶,調用函數SAMGR_SendResponseByIdentity進行響應。GetTaskConfig函數用于獲取任務配置。
⑴ typedef enum BootMessage { /** Message indicating that the core system service is initialized */ /** 標識核心系統服務初始化完成 */ BOOT_SYS_COMPLETED, /** Message indicating that the system and application-layer services are initialized */ /** 標識應用層服務初始化完成 */ BOOT_APP_COMPLETED, /** Message indicating service registration during running */ /** 標識運行時的服務注冊 */ BOOT_REG_SERVICE, /** Maximum number of message IDs */ /** 標識消息最大值,butt是煙蒂;屁股;槍托的意思,表示尾部吧 */ BOOTSTRAP_BUTT } BootMessage; ...... static BOOL MessageHandle(Service *service, Request *request) { Bootstrap *bootstrap = (Bootstrap *)service; switch (request->msgId) { case BOOT_SYS_COMPLETED: ⑵ if ((bootstrap->flag & LOAD_FLAG) != LOAD_FLAG) { INIT_APP_CALL(service); INIT_APP_CALL(feature); bootstrap->flag |= LOAD_FLAG; } ⑶ (void)SAMGR_SendResponseByIdentity(&bootstrap->identity, request, NULL); break; case BOOT_APP_COMPLETED: (void)SAMGR_SendResponseByIdentity(&bootstrap->identity, request, NULL); break; case BOOT_REG_SERVICE: (void)SAMGR_SendResponseByIdentity(&bootstrap->identity, request, NULL); break; default: break; } return TRUE; } static TaskConfig GetTaskConfig(Service *service) { (void)service; // The bootstrap service uses a stack of 2 KB (0x800) in size and a queue of 20 elements. // You can adjust it according to the actual situation. TaskConfig config = {LEVEL_HIGH, PRI_NORMAL, 0x800, 20, SHARED_TASK}; return config; }
參考站點
OpenHarmony / startup_bootstrap_lite
HarmonyOS Device > 文檔 > 指南 > 基礎能力: bootstrap服務啟動組件
啟動恢復子系統.md
輕量帶屏解決方案之恒玄芯片移植案例
小結
本文介紹了startup子系統之bootstrap_lite服務啟動引導部件的移植適配案例及原理。因為時間關系,倉促寫作,或能力限制,若有失誤之處,請各位讀者多多指正。感謝閱讀,有什么問題,請留言。
Bootstrap IoT 輕量級操作系統 LiteOS
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。