OHOS 3.1的Init进程two_stages相关分析-1-编译部分 原创 精华

liangkz_梁开祝
发布于 2022-5-7 11:10
浏览
3收藏

::: hljs-center

OHOS 3.1的Init进程two_stages相关分析-1-编译部分

:::

::: hljs-center

梁开祝 2022.05.04

:::

:本文可做为《沉浸式剖析OpenHarmony源代码》一书的第5章的5.4小节部分内容的大纲或草稿。】

OHOS LTS3.0版本的标准系统还不支持two_stages,3.1版本开始支持。这里的two_stages是指OHOS 3.1之后的标准系统,从内核态切换到用户态运行init进程时,分成两个stages来完成系统的启动工作:

  • stage0运行在ramdisk中,主要是生成设备节点、挂载根文件系统,并切换到stage1去运行;
  • stage1完成OHOS框架各模块、各进程的启动工作。

不过,OHOS 3.1标准系统烧录到HI3516DV300开发板,跑起来相当吃力,因此本文将基于DAYU200开发板,分别从编译和实现两大部分来对two_stages展开分析,最后再通过log确认一遍相关流程。

【本文很长,分两篇文章来发布:编译部分实现部分

1.编译部分

1.1 OHOS 3.1简明编译流程

请先去《OHOS3.1 简明编译流程》阅读和简单了解一下OHOS3.1系统的编译流程。

1.2 GN阶段与Ramdisk相关部分

在《OHOS3.1 简明编译流程》的“6.gn”步骤会执行“gn_gen”去预处理所有的.gn文件,生成对应的.ninja文件。其中与ramdisk相关的部分(局部),如下图1所示。
OHOS 3.1的Init进程two_stages相关分析-1-编译部分-鸿蒙开发者社区

在//productdefine/common/device/rk3568.json文件里,定义了enable_ramdisk为true,它将会作为全局参数引入RK3568项目的编译流程中。

GN执行到//device/board/hihope/rk3568/BUILD.gn时,这里的group(“rk3568_group”)的deps关系中,就有对enable_ramdisk的判断和使用。其中的:

  • “cfg:init_configs”:会拷贝fstab.required文件到//out/rk3568/目录下备用,也会把ramdisk_resource_config.ini文件拷贝到//out/rk3568/packages/phone/目录下备用。
    注意,这里不再把ramdisk_resource_config.ini文件拷贝到//build/ohos/images/mkimage/目录下了,可以避免出现文章《OHOS3.1 cannot stat 'packages/phone/…/…/…/…/ramdisk.img》中描述的异常。
  • “kernel:kernel”:里面的action(“kernel”)会在后面的内核编译阶段执行"build_kernel.sh"脚本,enable_ramdisk将作为其中一个参数参与编译内核。
  • “updater:updater_files”:这一步会把会把updater_ramdisk_resource_config.ini文件拷贝到//out/rk3568/packages/phone/目录下备用。【后文暂不深入对updater_ramdisk_resource_config.ini进行分析】


在gn_gen阶段,//build/core/gn/BUILD.gn中还定义了group(“packages”)和group(“images”) ,其中的make_packages和make_images的动作,是在ninja的最后阶段去执行的,enable_ramdisk也作为重要的参数去生成烧录镜像,如下图2所示。
OHOS 3.1的Init进程two_stages相关分析-1-编译部分-鸿蒙开发者社区

1.3 Ninja阶段与Ramdisk相关部分

在《OHOS3.1 简明编译流程》的“6.ninja”步骤会执行“ninja”程序,根据上一步生成的.ninja文件去生成所有的中间文件(.a/.o/.so/配置文件/可执行文件…)。

1.3.1 group(“rk3568_group”)

在执行到group(“rk3568_group”)时,会将fstab.required、ramdisk_resource_config.ini等文件拷贝到对应的目录备用。

1.3.2 action(“kernel”)

在执行到action(“kernel”)时,会执行build_kernel.sh去编译内核,并把resource.img、parameter.txt、MiniLoaderAll.bin、uboot.img、config.cfg等文件拷贝到//out/rk3568/packages/phone/images/中,注意:

if [ “enable_ramdisk” != “${6}” ]; then
cp ${KERNEL_OBJ_TMP_PATH}/boot_linux.img ${2}/boot_linux.img
fi

这里是不支持enable_ramdisk时,才会直接拷贝boot_linux.img;支持enable_ramdisk的话,这里先不拷贝,等后面group(“images”)阶段生成ramdisk.img时才会通过执行make-boot.sh,去重新生成boot_linux.img并拷贝到//out/rk3568/packages/phone/images/中。
OHOS 3.1的Init进程two_stages相关分析-1-编译部分-鸿蒙开发者社区
如上图所示,前面5个文件都是在build_kernel.sh时拷贝到这里的;后面5个.img文件,除了boot_linux.img是在make-boot.sh生成并拷贝到这里之外,其余4个都是group(“images”)阶段执行build_image.py脚本生成并拷贝到这里的。

1.3.3 group(“packages”)

在执行到group(“packages”)时,其中一步会执行modules_install.py脚本,先删除//out/rk3568/packages/phone/目录下已存在的system、vendor、updater、ramdisk等目录,并重新生成它们。
此时注意看ramdisk和system子目录下的内容,用tree命令将其目录树结构打印出来,如下:
OHOS 3.1的Init进程two_stages相关分析-1-编译部分-鸿蒙开发者社区
这里顺便把root、userdata、vendor、updater子目录的一级目录结构放上来做一下对比和参考。
OHOS 3.1的Init进程two_stages相关分析-1-编译部分-鸿蒙开发者社区
上两图中,共计有三个init可执行程序:

  • ramdisk子目录下的init(暂标记为initA)可执行程序
  • system子目录下的init(暂标记为initB)可执行程序
  • updater子目录下的init(暂标记为initA’)可执行程序
    三者bit-to-bit的,你可以认为它们是同一个可执行程序的三份拷贝,它们都是由//base/startup/init_lite/目录下的代码编译出来的init可执行程序。

    但是,从另外一个角度来看,initA、initB、initA’是三个完全不同的可执行程序!!!这个会在实现部分做详细说明。

1.3.4 group(“images”)

在执行到group(“images”)时,会执行build_image.py脚本去生成ramdisk.img、system.img、vendor.img、userdata.img镜像。

通过参数确定需要生成哪个image,先删除已经存在的image,再重新生成对应的子目录和link文件,执行mkimages.py去make具体的image。

mkimages.py会根据参数先加载config_file,即xxx_image_conf.txt文件,根据文件内的fs_type参数决定调用哪个工具(mkf2fsimage.pymkextimage.pymkcpioimage.py)去生成对应的image。xxx_image_conf.txt和dac.txt文件的使用说明,见同目录下的README.txt文件。

生成这些镜像的简单流程,可以参考1.2小节的图2的右半部分。

  • 生成ramdisk.img
    流程见1.2小节的图2的右半部分,分成三步:
    [3-1] 根据ramdisk_resource_config.ini的描述,通过cpio工具将//out/rk3568/packages/phone/ramdisk/目录打包成//out/rk3568/ramdisk.img。
    [3-2] 执行make-boot.sh,将//out/rk3568/ramdisk.img拷贝到//out/kernel/src_tmp/linux-5.10/boot_linux/extlinux/目录下,根据同目录下的extlinux.conf的描述,用mke2fs工具生成boot_linux.img,并拷贝到//out/rk3568/packages/phone/images/目录下。
    [3-3] 支持two_stages时,这一步并不跑,直接return 0了。

    这里生成的boot_linux.img镜像,我没有仔细研究镜像制作的细节,不大清楚img内部结构具体是什么样的,但大概估计一下,可能如下:
    OHOS 3.1的Init进程two_stages相关分析-1-编译部分-鸿蒙开发者社区

  • 生成system.img
    生成system.img,也可以参考1.2小节的图2的右半部分,具体流程图我就不画了。
    mk_images()会先调用build_rootdir(src_dir),来把root目录和system目录拼接在一起,再调用mkextimage.py将它们制作成ext4格式的system.img。我没有仔细研究镜像制作的细节,不大清楚img内部结构具体是什么样的,但大概估计一下,可能如下:
    OHOS 3.1的Init进程two_stages相关分析-1-编译部分-鸿蒙开发者社区

    生成其它的images的过程,请小伙伴们自行分析一下。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-5-7 11:10:27修改
1
收藏 3
回复
举报
1条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

感谢大佬为OHOS 3.1开路,期待大佬接下来创作!

回复
2022-5-7 15:15:18
回复
    相关推荐