文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Hi3861_WiFi IoT工程:理解启动恢复子系统

2024-12-03 05:19

关注

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

Hi3861_WiFiIoT工程的一点理解

目录

更新记录:

5.理解启动恢复子系统

这是一个非常重要的子系统,我在之前《鸿蒙系统的启动流程》一文中做过一些简单的分析,建议先去看一下《鸿蒙系统的启动流程v3.0》Part 1/2的3/4章节。这里就先到鸿蒙系统来整体看一下它具体是怎么回事,然后再回到本工程来对比看hpm的裁剪给我们留下了什么。

仍然是先看官方readme 和重新整理目录结构。

  1. 启动恢复子系统负责从内核启动之后到应用启动之前的系统关键服务进程的启动过程以及设备恢复出厂设置的功能。涉及以下组件: 
  2.  
  3. init启动引导组件 
  4. init启动引导组件对应的进程为init进程,是内核完成初始化后启动的第一个用户态进程。init进程启动之后,读取init.cfg配置文 件,根据解析结果,执行相应命令并依次启动各关键系统服务进程,在启动系统服务进程的同时设置其对应权限。 
  5.  
  6. appspawn应用孵化组件 
  7. 负责接收用户程序框架的命令孵化应用进程,设置新进程的权限,并调用应用程序框架的入口函数。 
  8.  
  9. bootstrap服务启动组件 
  10. 提供了各服务和功能的启动入口标识。在SAMGR启动时,会调用boostrap标识的入口函数,并启动系统服务。 
  11.  
  12. syspara系统属性组件 
  13. 系统属性组件,根据HarmonyOS产品兼容性规范提供获取设备信息的接口,如:产品名、品牌名、厂家名等,同时提供设置/读 取系统属性的接口。 
  14.  
  15. startup启动组件 
  16. 负责提供大型系统(参考内存≥1GB)获取与设置操作系统相关的系统属性。 
  17.  
  18. 大型系统支持的系统属性包括:设备信息如设备类型、产品名称等,系统信息如系统版本、API版本等默认系统属性。 

两相比较就可以看到Hi3861工程相对于完整系统裁剪掉了appspawn_lite 和 init_lite两个组件(先灰化掉了),因为启动方式/流程上有比较大的差别,裁掉init_lite其实很容易理解,但为什么裁掉appspawn_lite我还没仔细研究。

这里就只分析Hi3861的bootstrap_lite,至于syspara_lite比较简单,看官方文档照着上表右边的调用顺序就可以获取属性信息了。appspawn_lite 和 init_lite两个组件,待我把相关细节搞清楚了,再完善到《鸿蒙系统的启动流程》的更新版本中,或者单独写一个理解总结出来。

下面的文字,其实也算是《鸿蒙系统的启动流程v3.0》Part 2的“4.第四阶段:鸿蒙系统框架层的启动”的完整分析版本。

官方readme 对bootstrap服务启动组件的描述就两句话,该怎么理解:

“提供了各服务和功能的启动入口标识。” 就是指在//base/startup/services/bootstrap_lite/source/core_main.h 头文件中定义的宏:SYS_INIT(name)和MODULE_INIT(name)。

“在SAMGR启动时,会调用boostrap标识的入口函数,并启动系统服务。”就是指在system_init.c文件中的HOS_SystemInit()函数调用 SAMGR_Bootstrap(); 去启动系统服务了。什么是“boostrap标识的入口函数”,我们在下面会解释。

  1. void HOS_SystemInit(void) 
  2.  
  3.  
  4.     MODULE_INIT(bsp);       
  5.  
  6.     MODULE_INIT(device); 
  7.  
  8.     MODULE_INIT(core); 
  9.  
  10.     SYS_INIT(service);     //#A 
  11.  
  12.     SYS_INIT(feature); 
  13.  
  14.     MODULE_INIT(run);   //#B 
  15.  
  16.     SAMGR_Bootstrap();   //#C 
  17.  

灰掉部分目前我还未涉足,先跳过,但要是理解了下面的内容,灰掉部分也就基本上理解了。

5.1 #A分析SYS_INIT(service)

打开//base/startup/services/bootstrap_lite/source/core_main.h 文件,工程编译是使用gcc编译器的,所以__GNUC__是有定义的。

把service代进去展开一下:

  1. #define SYS_INIT(service)     \ 
  2.     do {                   \ 
  3.         SYS_CALL(service, 0); \ 
  4.     } while (0) 
  5.  
  6. #define SYS_CALL(service, 0)                              \ 
  7.     do {                                              \ 
  8.         InitCall *initcall = (InitCall *)(SYS_BEGIN(service, 0));   \ 
  9.         InitCall *initend = (InitCall *)(SYS_END(service, 0));    \ 
  10.         for (; initcall < initend; initcall++) {                  \ 
  11.             (*initcall)();                                \ 
  12.         }                                            \ 
  13.     } while (0) 

SYS_BEGIN和SYS_END就不展开了,重点在for循环,可能还是不太好理解,我再把它翻译成大白话:

  1. for循环就是从 initcall 地址开始,到 initend地址(不含)结束, 
  2.  
  3. 依次调用*initcall内的地址所指向的函数,执行函数内的指令。 
  4.  
  5. initcall 是一个指针,其内容 *initcall是符号__zinitcall_sys_service_start的地址,即 &__zinitcall_sys_service_start, 
  6.  
  7. initend 是一个指针,其内容 *initend 是符号__zinitcall_sys_service_end的地址,即 &__zinitcall_sys_service_end 

Hi3516/Hi3518平台工程,打开 build\lite\platform\......\link.ld

Hi3861工程则是 vendor\hisi\hi3861\hi3861\build\link\link.ld.S

可以看到上面的 start/end 符号,但估计你打开文件,看到里面的东西,心里还是会有很大的问号。

那就直接去看编译后输出的map文件:out\wifiiot\Hi3861_wifiiot_app.map,文本编辑器打开该文件,搜索一下:

这里有三个service 要 init,从抓回来的log看,确实如此:

这下应该够清楚了吧?

SYS_INIT(service) 是调用端的宏,对应的,定义端也有一个对应的宏SYS_SERVICE_INIT(xxx)。

工程代码全局搜索一下“SYS_SERVICE_INIT”,把没什么用的 sample和 .h中的先去掉,就得到四个:

前三个就是上面的三个service。

第四个“SYS_SERVICE_INIT(InitializeRegistry);”在

foundation\distributedschedule\services\samgr_lite\samgr_server\source\samgr_server.c 文件中,

看它的 BUILD.gn 文件“shared_library("server")”,再到上级目录查看BUILD.gn,

  1. if (ohos_kernel_type == "liteos_a" || ohos_kernel_type == "linux"){ 
  2.     features += [ 
  3.         "samgr_server:server"
  4.         "samgr_client:client"
  5.     ] 

这是LiteOS_A或Linux内核的平台才会有的,所以Hi3861平台的log上看不到这个server的log。

上面的三个service使用的宏SYS_SERVICE_INIT(Init),我们也一步一步展开,

  1. #define SYS_SERVICE_INIT(func)  LAYER_INITCALL_DEF(func, sys_service, "sys.service"
  2. #define LAYER_INITCALL_DEF(func, layer, clayer) \ 
  3.     LAYER_INITCALL(func, layer, clayer, 2)         //默认优先级 2 
  4. #define LAYER_INITCALL(func, layer, clayer, priority)            \ 
  5.     static const InitCall USED_ATTR __zinitcall_##layer##_##func \ 
  6.         __attribute__((section(".zinitcall." clayer #priority ".init"))) = func 

__attribute__((section(“section_name”))) 其作用是将函数或数据放入指定名为"section_name"对应的段中。

最后分别得到:

  1. //.zinitcall.sys.service2.init = Init  //bootstrap_service 的Init 
  2.  
  3. //.zinitcall.sys.service2.init = Init  //broadcast_service 的Init 
  4.  
  5. //.zinitcall.sys.service2.init = Init  //hiview_service 的Init 

编译器根据attribute+section关键字,就把三个Init函数全都编译链接到了 .zinitcall.sys.service2.init 对应的段中,

结果就是上面Hi3861_wifiiot_app.map文件截图的样子。

5.2 #B分析MODULE_INIT(run)

对于MODULE_INIT(Xxx) 和对应的SYS_RUN(Xxx)的分析,和上面没什么差别,只是编译链接的时候,将函数放到不同的段中去而已。

我在应用层放了两个APP,分别是helloworld和led_example,log中也看到对应的log了。

5.3 #C分析SAMGR_Bootstrap()

SAMGER:system ability manager。系统服务框架子系统,这是一个非常核心的子系统了,我会另开一章来分析。不过这里还是先简单了解一下它在这一步,做了些什么事情。

先看官方文档:

由于平台资源有限,且硬件平台多样,因此需要屏蔽不同硬件架构和平台资源的不同、以及运行形态的不同,提供统一化的系统服务开发框架[system ability (SA) framework]。根据RISC-V、Cortex-M、Cortex-A不同硬件平台,分为两种硬件平台,以下简称M核、A核。

系统服务框架基于面向服务的架构,提供了服务开发、服务的子功能开发、对外接口的开发、以及多服务共进程、进程间服务调用等开发能力。其中:

约束

再看一个完整一点的log:

看log,在 SYS_INIT(service) 这一步,bootstrap_service 首先init,

打开 base\startup\services\bootstrap_lite\source\bootstrap_service.c 查看它的 Init 函数,

  1. static void Init(void) 
  2.     static Bootstrap bootstrap; 
  3.     bootstrap.GetName            = GetName; 
  4.     bootstrap.Initialize              = Initialize; 
  5.     bootstrap.MessageHandle  = MessageHandle; 
  6.     bootstrap.GetTaskConfig    = GetTaskConfig; 
  7.     bootstrap.flag = FALSE
  8.     printf("[bootstrap_service] SYS_SERVICE_INIT(Init).\n"); 
  9.  
  10.     SAMGR_GetInstance()->RegisterService((Service *)&bootstrap); 

它会先去get一个SAMGR的instance实例,向这个实例注册bootstrap服务。

进入SAMGR_GetInstance(),在 foundation\distributedschedule\services\samgr_lite\samgr\source\samgr_lite.c文件中:

bootstrap_service 是第一个调用SAMGR_GetInstance() 的服务,这时候全局变量g_samgrImpl还没有初始化,所以就要先init,然后就可以返回instance给Bootstrap 注册服务用了,后面的broadcast_service、hiview_service在 init时,直接就可以拿到instance去注册了。

全局变量g_samgrImpl记录了向它注册的所有服务的信息,包括了一组四个函数:

GetName/Initialize/MessageHandle/GetTaskConfig,这就是上面提到的“boostrap标识的入口函数”。

bootstrap_service、broadcast_service、hiview_service在SYS_INIT(service)这一步只能做很简单的注册服务的事情,否则会导致后面的INIT受阻。

在SAMGR_Bootstrap(); 这一步时,SAMGR才会真正根据注册在g_samgrImpl的信息,逐一为已注册的服务创建和分配资源,InitializeAllServices,AddTaskPool,SAMGR_StartTaskPool,SAMGR_SendSharedDirectRequest等待系统调度,然后在HandleInitRequest中才真正调用各自serveice注册的Initialize接口去完成服务的启动,为系统提供服务。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

来源:鸿蒙社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯