[HarmonyOS之旅] Chapter4 - HarmonyOS启动流程

codinglab 2020-12-19 11:23:50 6328
Hi,大家周末好呀。今天我们来看看Harmonyos是怎么样启动。

程序入口:main和app_main的那些事

玩过liteos的同学都比较熟悉了,liteos的内核启动后的第一个程序入口是app_main(),小A根据经验推测目前HarmonyOS的应用程序入口函数也是app_main(), 如何证明呢?其实如果小伙伴们留意的话,在之前vscode的调试配置中有这么一项

image-20201219094153686

其实就可以说明应用程序的入口是就是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的原因),有两处。

第一处:

image-20201219095609912

根据这一段汇编,我们可以知道,一个叫做start_falsh_data_loop的函数在最后跳转到main函数了。另外根据这三段汇编,我们可以大致猜测,他们做的事情就是,把代码从flash拷贝到ram中,然后执行程序。因此这里的main就是这个系统的入口函数了。

第二处:

image-20201219095550565

这是整个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,通过源码我们并没有找到这个的实现,那我们继续看汇编好了。

image-20201219102301372

小伙伴们看到了没有,这里就出现了我们想要的app_main啦😏,应用程序的入口就由此可以确定了。

应用的初始化

image-20201219103149162

这是app_main的函数主体,这里我们可以看到这个和我们上一篇的大致分析是一致的,只能匹配到很少的一部分,那么我们来看下HOS_SystemInit();这个接口。

image-20201219104808915

#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();
}

image-20201219110630453

这是执行的结果,是不是很奇怪,我们明明没有在HOS_SystemInit中调用HelloWorld,怎么会在start和end之间被执行到了呢?

总结:

其实上面问题的答案就藏在马赛克里面,欲知后事如何,那么且听下回分解吧😛。

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
codinglab
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区