鸿蒙系统源码main函数,鸿蒙系统的启动流程,建议收藏!

原标题:鸿蒙系统的启动流程,建议收藏!

声明:严格来说本文档并非真正原创的,这是上了朱有鹏老师的免费课《想读懂鸿蒙 2.0 源码,也许你需要先懂这些》之后,做的一些总结。

12a3087f185bf3eb8b9e1987c38867e8.png

课程时间一个半小时,内容也很多,学习过程中我发现朱老师的 PPT 上部分代码/文件,在我本地的鸿蒙系统代码上找不到,或者路径不相同,所以我就做了一些整理。

这里仅摘取课程中的鸿蒙系统在 HI3516DV300 平台上的启动流程部分(从 30:00 开始讲解启动过程)进行汇总和整理,如有错误,请朱老师和各位同学指正。后继在学习过程中会继续对本文当作修正升级。

我的本地代码是基于最新发布的 OpenHarmony 1.1.0 LTS(2021-04-01) 版本抓取的,代码根目录 OHOS1_1_0LTS:

$repo init -u https: //gitee.com/openharmony/manifest.git -b refs/tags/OpenHarmony_release_v1. 1.0-- no-repo-verify

$repo sync

在根目录下执行:

OHOS1_1_0LTS$ hb set

[OHOS INFO] Inputcode path: .

OHOS Which product doyou need?

->ipcamera_hispark_taurus@hisilicon

OHOS1_1_0LTS$ hb build

即可开始编译 hi3516dv300 平台代码。输出的过程文件和最终 bin,在以下路径内:

outhispark_taurusipcamera_hispark_taurus

因为本人还没有开发板,无法烧录、抓取 log 分析以及做相关的操作去验证。

01

U-Boot 启动

System startup

Uncompress Ok!

U-Boot 2016.11(......) hi3516dv300

............

............(省略)

Hit any keytostopautoboot: 0

MMC read: dev #0, block # 2048, count 16384 ... 16384 blocks read: OK

## Starting application at 0x80000000...

到此为止属于 U-Boot 的启动。Uboot 不属于鸿蒙系统,这里不做进一步分析,代码在目录:

devicehisiliconthird_partyubootu-boot-2020.01

02

汇编代码引导 LiteOS-a 内核

Uboot 引导 liteos-a 内核启动起来,需要有一个入口,在:

kernelliteos_atoolsbuildliteos.ld

打开这个文件,可见:

ENTRY(reset_vector)

INCLUDEboard.ld

SECTIONS

{

......

}

reset_vector 就是整个鸿蒙内核启动的入口点,这是一个符号,定义在:

kernelliteos_aarcharmarmsrcstartupreset_vector_mp.S

同目录下还有一个 reset_vector_up.S 文件,因为 HI3516 是 ARM Cortex A7 双核处理器,所以需要看 mp(多核)这个文件,up 这个是单核的。

打开 reset_vector_mp.S 文件,找到“reset_vector:”符号,从这里开始跑汇编代码,引导 liteos-a 内核的启动,一直到:

bl main

_start_hang:

b _start_hang

这里调用一个 main 函数,然后执行 _start_hang 进入死循环,至此汇编代码阶段就结束了。通过 main 函数进入内核 LiteOS-a 启动的 C 语言阶段。

03

内核 LiteOS-a 的 C 语言启动阶段

上面汇编阶段调用的 main 函数,位于:

kernelliteos_aplatformmain.c

main 函数通过 OsSystemInfo; 函数里打印下面这些信息:

******************Welcome******************

Processor : Cortex-A7*2

Run Mode : SMP

GIC Rev : GICv2

build time : ......

Kernel : Huawei LiteOS 2.0.0.xxx

********************************************

main core booting up...

...

...

从这一步的 main 开始读 liteos-a 的 C 语言源码,可以直接在鸿蒙代码的

kernelliteos_aplatformmain.c

进行阅读理解。不过,推荐从下面仓库拉代码下来读,鸿蒙内核源码注解分析:

https: //gitee.com/weharmony/kernel_liteos_a_note.git

这是在鸿蒙官方开源项目 kernel_liteos_a 基础上,给源代码加上了给常详细的中文注解,有利于加快理解。

main 函数截图如下:

Line173 行调用的 OsMain 函数,位于:

kenerlliteos_akernelcommonlos_config.c

主要做了:

08ed0bb2c54aba20333082cde032bb82.png

其中的:

①OsTickInit(......); // tick 初始化,包含注册中断事件,硬件时钟初始化,启动节拍,注册硬中断。

②OsKernelInitProcess; // 完成内核进程的初始化,调用:

OsProcessCreateInit(processCB, OS_KERNEL_MODE, "KProcess", 0);

首先创建 2 号进程 KProcess,最高优先级 0,这是一个内核态进程。鸿蒙进程一共有 32 个优先级(0-31),其中 0-9 级为内核进程,用户进程可配置的优先级有 22 个(10-31)。

然后创建 2 号进程的 2 个子线程 ResourceTask 和 KIdle,详见代码。可以在 shell 内执行 task 命令查看进程和线程信息,表格见文末。

注意,此时 1 号进程还没有创建,它是用户态根进程,要到稍微后面才创建。

③OsSwtmrInit; //软时钟模块初始化,创建 Swt_Task(software timmer) 线程,父进程是 2 号进程 KProcess。

④OsSystemInit; //系统初始化,系统软硬件的初始化,由 2 号进程 KProcess 创建“system_wq”“SystemInit”“memshow_Task”等线程。

“SystemInit”线程:

7264c8b6917e5e8fff5f0fac010fd1a5.png

其入口函数则由内核外部提供,在:

devicehisiliconhispark_taurussdk_liteosmppmodule_initsrcsystem_init.c

里的 SystemInit 函数:

8d97ea0c137f68d55fbef6310633bb12.png

其中的:

①ProcFsInit,创建和挂载/proc 文件系统,代码见:

kernelliteos_afsprocos_adeptproc_init.c

②SDK_init //calling SDK_init form HISI_SDK,初始化 3516DV300 特有的 SDK,用内部的 DSP 硬件来做视频编解码,只提供相关库文件,不开源。

代码在:

devicehisiliconhispark_taurussdk_liteosmppmodule_initsrcsdk_init.c

③OsMountRootfs,挂载根文件系统:

outhispark_taurusipcamera_hispark_taurusrootfs.tar

可以通过 tar -tf rootfs.tar 命令查看里面都有些什么内容。开始查找根文件系统里的 /bin/init 并创建 init 进程。

④OsUserInitProcess,调用:

OsProcessCreateInit(processCB, OS_USER_MODE, "Init", OS_PROCESS_USERINIT_PRIORITY); //28

这时候才创建 1 号进程 init,这是用户态根进程,优先级别为 28,这个 1 号进程接下来会创建和启动其他的用户态进程(shell/apphilogcat/.../ai_server等 3~9 号进程)。

接下来这一小部分还没理解透,调用 OsLoadUserInit load init 的相关配置:

3cce4638f6c1807f8756ea17d4ca14ca.png

再使用 __user_init_entry 参数,调用OsUserInitProcessStart。

92c6e3937a314bc7a1d64f0b2aed3b26.png

__user_init_entry 就是第一个用户态根进程的地址,它通过宏 LITE_USER_SEC_ENTRY 进行定义,代码在:

kernelliteos_akernelusersrclos_user_init.c

2998fa9c714046ff220687fcd20685f9.png

/bin/init 就是 kernel 调用 init_lite的入口【见第四阶段对这个的解释】,由此进入应用层的启动。跑完 OsMain 函数,LiteOS-a 内核的启动工作就基本上完成了,接下来就开始了鸿蒙系统应用层的启动。

04

鸿蒙系统应用层的启动

这个应用层实际上就是鸿蒙的 framework,启动 init 入口在:

basestartupinit_liteservicessrcmain.c

09d9a9a031c264443d0571b64e25a029.png

①ReadFileToBuf

这一步读取的 /etc/init.cfg 文件,在上面 OsMountRootfs 挂载根文件系统的时候就挂载上了,它是:

vendorhisiliconhispark_taurusinit_configsinit_liteos_a_3516dv300.cfg

的副本,这个文件就包含了“pre-init”“init”“post-init”的相关操作,分别是设置挂载一些设备、设置好路径,启动服务等工作。

而后面的"services"则包含一组服务的定义,它们是系统里的关键进程。

e79a680e756094fa1739ddab77cfc725.png

②DoJob("init")

由“1 号进程 init”,在应用层通过 start 指令创建和启动:shell/apphilogcat/.../ai_server 等 3~9 号进程,它们都是用户态进程,父进程都是“1 号进程 init”。

init 将根据上面 cfg 配置的 job 和 services 来做对应的操作和启动对应的服务程序,并设置它们的 uid、gid、进程优先级和权限等。

可以在 shell 内执行 task 命令查看进程和线程信息,表格见文末。

见官方文档:

basestartupinit_liteREADME_zh.md

这个 init 组件(即 basestartupinit_lite)负责处理从内核加载第一个用户态进程(2 号进程 init)开始,到第一个应用程序启动之间的系统服务进程启动过程。

init 将系统启动分为三个阶段:

“pre-init”阶段: 启动系统服务之前需要先执行的操作,例如挂载文件系统、创建文件夹、修改权限等。

“init”阶段: 系统服务启动阶段。

“post-init”阶段: 系统服务启动完后还需要执行的操作。

上述每个阶段在配置文件 init.cfg 中都用一个 job 表示,每个 job 都对应一个命令集合,init 通过依次执行每个 job 中的命令来完成系统初始化。

job 执行顺序:先执行“pre-init”,再执行“init”,最后执行“post-init”,所有 job 都集中放在 init.cfg 的 jobs 数组中。

除上述 jobs 数组之外,init.cfg 中还有一个 services 数组,用于存放所有需要由 init 进程启动的系统关键服务的服务名、可执行文件路径、权限和其他属性信息。

配置文件 init.cfg 位于代码仓库 /vendor/hisilicon/hispark_aries/init_configs/ 目录,部署在 /etc/ 下,采用 json 格式,文件大小目前限制在 100KB 以内。

init 组件会编译成 outhispark_taurusipcamera_hispark_taurus 目录下的 bin/init,同时打包在根文件系统 rootfs.tar 内,上面挂载根文件系统时,会挂载成 /bin/init,由第三阶段的最后一步 OsUserInit 调用和执行。

见官方文档:

basestartupinit_liteREADME_zh.md

至此,鸿蒙系统的关键系统进程和相关服务都已经启动起来了,至于 shell/apphilogcat/.../ai_server 等 3~9 号进程的具体启动过程和调用的相关代码入口,还需待后面进一步学习分析。

05

鸿蒙应用(APP)的启动

在 Hi3516dv300 平台(带屏幕)的桌面(也就是 launcher 进程)上点击 camera 应用图标,这时候会启动 camera 应用程序,实际上会通过“7 号进程 appspawn”创建子进程“com.huawei.camera”。

这是一个应用程序进程,其父进程并不是 launcher 进程,而是 appspawn 进程。

实际上所有的应用程序的父进程都是 appspawn 进程。

鸿蒙应用开发的第一个示例程序“helloworld”的启动也应该类似。

# include

# include"ohos_init.h"

# include"ohos_types.h"

voidHelloWorld( void)

{

printf( "[Init] Hello World!n");

}

SYS_RUN(HelloWorld);

关于 SYS_RUN 如何运作,以便让 HelloWorld 运行起来,其他老师有非常详细的解释,这里不再复述。

06

#task命令查看进程/线程信息(简表)

3951f422d4ffd0cf63be30c70b821ff2.png

326245a652a079c61992a5f707ad2b98.png

a5abffd54cfffcc6c2868e7bf6ebf0c2.png

本周六,上海市浦东新区卓美亚喜马拉雅酒店 3 楼宴会厅,鸿蒙人专属的华为开发者日(HDD)来啦!

技术干货+现场鸿蒙场景沉浸体验+全天 Codelab!报名还有鸿蒙官方周边送上哦!

👇扫码报名参与👇

如果没法去线下的话返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值