[HarmonyOS之旅] Chapter4 - HarmonyOS启动流程
Hi,大家周末好呀。今天我们来看看Harmonyos是怎么样启动。
程序入口:main和app_main的那些事
玩过liteos的同学都比较熟悉了,liteos的内核启动后的第一个程序入口是app_main(),小A根据经验推测目前HarmonyOS的应用程序入口函数也是app_main(), 如何证明呢?其实如果小伙伴们留意的话,在之前vscode的调试配置中有这么一项
其实就可以说明应用程序的入口是就是app_main。那么这里有个问题了,为什么不是main为入口呢?Hi3861采用的是liteos-m核,而liteos的一个特点就是内核和应用的关系和linux的不一。Linux支持多进程,所以可以有多个main运行,而liteos并不支持多进程,那么其实内核和应用实际上就是一个整体的程序,而不是独立分开的,因此不能有多个main。那么问题来了,这么说的话,意思就是有了一个main入口,因此后面才使用app_main作为内核启动后的第一个程序入口。下面请看小A的证明😉。
在编译完成后,会生成这么一个文件out/wifiiot/Hi3861_wifiiot_app.asm,这就是app的汇编文件。我们打开看一看,很大很长。我们秉持着怀疑的态度,搜索一下 "< main >"(main前后其实无空格,这里是因为markdown的原因),有两处。
第一处:
根据这一段汇编,我们可以知道,一个叫做start_falsh_data_loop的函数在最后跳转到main函数了。另外根据这三段汇编,我们可以大致猜测,他们做的事情就是,把代码从flash拷贝到ram中,然后执行程序。因此这里的main就是这个系统的入口函数了。
第二处:
这是整个main函数的汇编体了,从中我们可以主要有调用以下函数:
hi_u32 change_uart(hi_uart uart_num);
hi_void hi_patch_init(hi_void);
uart_puts;
LITE_OS_SEC_TEXT void register_log_hook(OS_SENDCHR2CHL_HOOK_FUNC uartFun);
CheckChipVer;
OsBoardConfig;
LITE_OS_SEC_TEXT_INIT UINT32 LOS_KernelInit(VOID)
AppInit;
LITE_OS_SEC_TEXT_INIT UINT32 LOS_Start(VOID)
这一段的重点是 LOS_KernelInit、AppInit、LOS_Start这三个,根据这三个调用顺序,我们可以看到内核初始化后的第一件事情是AppInit,通过源码我们并没有找到这个的实现,那我们继续看汇编好了。
小伙伴们看到了没有,这里就出现了我们想要的app_main啦😏,应用程序的入口就由此可以确定了。
应用的初始化
这是app_main的函数主体,这里我们可以看到这个和我们上一篇的大致分析是一致的,只能匹配到很少的一部分,那么我们来看下HOS_SystemInit();这个接口。
#define SYS_INIT(name) \
do { \
SYS_CALL(name, 0); \
SYS_CALL(name, 1); \
SYS_CALL(name, 2); \
SYS_CALL(name, 3); \
SYS_CALL(name, 4); \
} while (0)
#define MODULE_INIT(name) \
do { \
MODULE_CALL(name, 0); \
MODULE_CALL(name, 1); \
MODULE_CALL(name, 2); \
MODULE_CALL(name, 3); \
MODULE_CALL(name, 4); \
} while (0)
#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++) { \
printf("init Func Address:%p\n", initcall); \
printf("Call Func Address:%p\n", *initcall); \
(*initcall)(); \
} \
} while (0)
很奇怪,SAMGR_Bootstrap()函数的调用之前,我们并没有明显的看到诸如log这样的模块的调用,那么类似模块的函数调用是怎么完成的呢?也许你会说,调用可能藏在别的地方,只是你没有分析到而已。Ok,那我们根据官方文档先来写个简化的Hello World先。
void HelloWorld(void)
{
printf("Codinglabs >>>>>> Hello HarnonyOS\n");
}
SYS_RUN(HelloWorld);
void HOS_SystemInit(void)
{
printf("%s %s %d \n", __FILE__, __FUNCTION__, __LINE__);
printf("Codinglabs >>>>>> start\n");
MODULE_INIT(bsp);
MODULE_INIT(device);
MODULE_INIT(core);
SYS_INIT(service);
SYS_INIT(feature);
MODULE_INIT(run);
printf("Codinglabs >>>>>> end\n");
SAMGR_Bootstrap();
}
这是执行的结果,是不是很奇怪,我们明明没有在HOS_SystemInit中调用HelloWorld,怎么会在start和end之间被执行到了呢?
总结:
其实上面问题的答案就藏在马赛克里面,欲知后事如何,那么且听下回分解吧😛。
- 分享
- 举报
-
浏览量:5435次2021-01-07 17:33:46
-
浏览量:5673次2020-12-23 09:56:49
-
浏览量:8526次2020-12-14 12:42:14
-
浏览量:9142次2020-12-15 21:43:52
-
浏览量:9433次2020-12-08 19:45:14
-
浏览量:9129次2020-12-12 09:47:20
-
浏览量:6303次2021-09-14 13:51:27
-
浏览量:5601次2021-09-18 13:38:23
-
浏览量:4423次2021-06-25 14:01:34
-
浏览量:5022次2021-07-30 15:32:45
-
浏览量:4372次2021-09-28 13:48:16
-
浏览量:4633次2021-07-08 14:45:19
-
浏览量:3502次2022-06-01 14:21:53
-
浏览量:994次2023-12-01 12:14:35
-
浏览量:735次2023-12-06 16:50:25
-
浏览量:1295次2023-12-04 13:11:50
-
浏览量:1457次2023-12-06 12:30:38
-
浏览量:7250次2021-07-06 16:30:09
-
浏览量:3762次2021-07-05 10:04:38
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
codinglab
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明