一、启动概述
在产品代码成功编译通过后,开始进行下一步的运行调测阶段,而运行调测第一步便需要了解系统的启动过程。对于 OpenHarmony 来说,系统启动流程如下:
---> uboot启动
---> uboot启动内核
---> 内核挂载根文件系统(此时为ramdisk文件系统)
---> 运行ramdisk中的第一个程序
---> 根据fstab中内容挂载文件系统
---> 切换root路径为/usr
---> 第一个程序为init则进行系统初始化
---> 第一个程序为init_early则通过execv启动init
关于 uboot 启动到内核挂载根文件系统部分属于 Linux 内容,这里不做介绍,以下我们开始来介绍从 ramdisk 启动的第一个程序,我们以 init_early 模式为例开启我们新的篇章
二、ramdisk 文件系统介绍
2.1 什么是 ramdisk 文件系统
ramdisk 是一种将内存中的的一块区域作为物理磁盘来使用的一种技术,也可以说,ramdisk 是在一块内存区 域中创建的块设备,用于存放文件系统。对于用户来说,可以把 ramdisk 与通常的硬盘分区同等对待来使用。ramdisk 不适合作为长期保存文件的介质,掉电后 ramdisk 的内容会消失。
2.2 ramdisk 文件系统和 ramdisk.img 有什么关系
在 Linux 中,根文件系统是需要挂载到实际的物理磁盘中的,而 ramdisk.img 便是 ramdisk 文件系统挂载的磁盘,即 ramdisk.img 是 ramdisk 文件系统的打包镜像。
可以对比 rootfs,我们通过 busybox 制作出来的是 rootfs 文件系统,但是实际启动使用的时候我们时我们需要将 rootfs 文件系统打包制作成 rootfs.ext4 一样。
三、init_early 程序介绍
3.1 init_early 程序注意事项
init_early 程序作为第一个启动的程序,由于当前挂载的文件系统为 ramdisk 文件系统,该系统的目的仅仅是为了拉起 OpenHarmony 真正的文件系统,可以说仅仅是为了 init_early 程序的运行,因此内部的库很少,仅有以下内容,所以 init_early 程序仅可以依赖以下这些库
wen_fei@rh-Z790-UD:~/OpenHarmony/dayu800-v4.1-release/out/dayu800/packages/phone/ramdisk/lib64
$ tree
.
├── chipset-pub-sdk
│ ├── libpcre2.z.so
│ ├── libsec_shared.z.so
│ └── libselinux.z.so
├── libclang_rt.asan.so
├── libc++.so
├── libc.so
├── libinit_module_engine.so -> libinit_stub_empty.so
├── libinit_stub_empty.so
├── libload_policy.z.so
└── platformsdk
└── librestorecon.z.so
3.2 为什么要有 init_early 程序
作为第一个基于 ramdisk 文件系统启动的程序,能够依赖的库有限,因此能实现的功能相对也不能复杂,通过使用 init_early 拉起 init 进程可以在尽可能减小 ramdisk.img 大小的同时很好的让 init 程序开发更加丰富的内容。
其次如果 init 程序加载有问题也可以通过 init_early 程序先启动到 shell,然后在 shell 中运行 init 进行调测。
以上内容均为个人猜想。
3.3 init_early 代码路径
该部分代码的编译参考:base/startup/init/services/init/standard/BUILD.gn
其 main 函数位于:base/startup/init/services/init/standard/main_early.c
3.4 init_early 代码介绍
从其 main_early.c 代码中可以看出 init_early 主要完成以下几个功能
-
忽略终端信号,将 SIGPIPE 交给系统处理
-
使能 InitLog 的 INIT_INFO 级别(非核心)
-
初始化 EarlyLog(非核心)
-
创建常用的文件和设备节点
-
执行钩子函数,一般钩子链表是通过__attribute__((constructor))构造的函数添加的
-
确实是否为升级模式
-
根据 ramdisk 镜像中的 fstab 文件挂载镜像
-
启动第二阶段 init
- 关闭 stdio(此时便不能通过 printf 打印 log)
- 切换 root 路径为/usr(system 文件系统)
- 让 init 程序代码当前的 init_early 程序进行
注意这里是程序不是进程,因为 init_early 在 ramdisk 中是软链接为 init,因此进程对应的是 init,而不是 init_early
四、init 启动介绍
4.1 init 运行前准备工作
由于 init_early 的铺垫,此时 init 启动的实际文件系统已经不在 ramdisk 文件系统中了,而是位于 system 文件系统中。因此链接库的路径指定是通过 etc/ld-musl-namespace-riscv64.ini 该文件中设置的路径按照顺序链接的,所以首先必须确定 system 镜像中是否有该文件。
在 init 程序中有很多函数通过 MODULE_CONSTRUCTOR 将其添加到了 Hook 链表中,在 init 实际运行的时候会调用 HOOK 的执行接口,将所有的预处理函数调用执行。
4.2 init 启动失败调测
如果 init_early 加载 init 程序运行直接失败,我们可以在 init_early 最后添加如下代码后让串口进入 shell,然后在 shell 中直接运行 init 跟踪定位
execv("/bin/sh", NULL);
4.3 init 启动的流程
这部分就通过 init 的 main 函数进行阅读理解了,注意 HOOK 链表项都是通过 MODULE_CONSTRUCTOR 接口在 main 函数执行前添加的,详细请了解 gcc 的 __attribute__((constructor))
属性
init 的 main 函数位于:base/startup/init/services/init/main.c
最后
小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为资料太多,太杂,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。
为了确保高效学习,建议规划清晰的学习路线,涵盖以下关键阶段:
→【纯血版鸿蒙全套最新学习资料】希望这一份鸿蒙学习资料能够给大家带来帮助~
鸿蒙(HarmonyOS NEXT)最新学习路线
该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案
路线图适合人群:
IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术
2.视频学习资料+学习PDF文档
HarmonyOS Next 最新全套视频教程 (鸿蒙语法ArkTS、TypeScript、ArkUI教程……)
纯血版鸿蒙全套学习资料(面试、文档、全套视频等)
鸿蒙APP开发必备
总结
总的来说,华为鸿蒙不再兼容安卓,对程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,才能在这个变革的时代中立于不败之地。