OpenHarmony开发者论坛

标题: 如何优雅的了解OpenHarmony-v4.1-Release的init启动流程 [打印本页]

作者: 润开鸿_闻飞    时间: 2024-5-22 17:49
标题: 如何优雅的了解OpenHarmony-v4.1-Release的init启动流程
[md][itopen组织](https://gitee.com/itopen)
1、提供OpenHarmony优雅实用的小工具
2、手把手适配riscv + qemu + linux的三方库移植
3、未来计划riscv + qemu + ohos的三方库移植 + 小程序开发
4、一切拥抱开源,拥抱国产化

# 一、启动概述

在产品代码成功编译通过后,开始进行下一步的运行调测阶段,而运行调测第一步便需要了解系统的启动过程。对于OpenHarmony来说,系统启动流程如下:

```shell
---> 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程序仅可以依赖以下这些库

```nginx
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跟踪定位

```nginx
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
[/md]
作者: conceptcon    时间: 2024-8-2 17:01
请教一下,我从RK官方下载的uboot,无法启动OpenHarmnoy5.0beta。但是可以启动OpenHarmnoy4.0。出错log提示,/bin/init文件不存在,帮忙看看。谢谢。
作者: 润开鸿_闻飞    时间: 2024-8-5 23:14
回复 conceptcon: 你用的是OpenHarmony的原生代码还是你有修改?





欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5