启动前准备
上电后首先通过汇编指令去加载uboot引导程序,然后由uboot从分区中加载内核镜像等,并启动内核。
而大致是在vmlinux的入口startup_32(head.S)中为pid号为0的原始进程设置了执行环境,然后原始进程开始执行start_kernel()完成Linux内核的初始化工作。包括初始化页表,初始化中断向量表,初始化系统时间等。继而调用 fork(),创建第一个用户进程:
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
这个进程就是著名的pid为1的init进程,它会继续完成剩下的初始化工作,然后execve(/sbin/init), 成为系统中的其他所有进程的祖先
当内核启动时,设置缓存、被保护存储器、计划列表、加载驱动。此外,还启动了Kernel的swapper进程(pid = 0)和kthreadd进程(pid = 2)。下面分别介绍下它们:
- swapper进程:又称为idle进程,系统初始化过程Kernel由无到有开创的第一个进程, 用于初始化进程管理、内存管理,加载Binder Driver、Display、Camera Driver等相关工作。idle进程是Linux系统第一个进程,是init进程和kthreadd进程的父进程
- init进程是Linux系统第一个用户进程,是Android系统应用程序的始祖,我们的app都是直接或间接以它为父
- kthreadd进程:Linux系统的内核进程,是所有内核进程的鼻祖,会创建内核工作线程kworkder,软中断线程ksoftirqd,thermal等内核守护进程
init和kthreadd由idle创建:
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 8216 2056 0 c7fffc10 S /init
root 2 0 0 0 0 00000000 S kthreadd
init进程又创建了以下核心服务进程
USER PID PPID VSIZE RSS WCHAN PC NAME
root 783 1 3024 1428 0 c7fffc10 S /sbin/ueventd #日志记录
root 1080 1 1124684 75268 0 c7f28c10 S zygote
system 1073 1 5868 2124 0 c7f28c10 S /system/bin/servicemanager
root 1074 1 48060 6116 0 c7f28c10 S /system/bin/surfaceflinger
audioserver 1081 1 41576 6788 0 c7f28c10 S /system/bin/audioserver
cameraserver 1082 1 36680 6140 0 c7f28c10 S /system/bin/cameraserver
media 1089 1 72824 12608 0 c7f28c10 S /system/bin/mediaserver
init 启动
init进程的启动会首先从init进程的入口函数开始,init进程的入口函数main位于system/core/init/main.cpp中,代码如下所示
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
#endif
// Boost prio which will be restored later
setpriority(PRIO_PROCESS, 0, -20);
if (!strcmp(basename(argv[0]), "ueventd")) { // 根据参数,判断是否需要启动 ueventd
return ueventd_main(argc, argv); // ueventd 主要是负责设备节点的创建、权限设定等一些列工作
}
// 当传入的参数个数大于 1 时,执行下面的几个操作
if (argc > 1) {
if (!strcmp(argv[1], "subcontext")) { // 参数为 subcontext,初始化日志系统
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap function_map;
return SubcontextMain(argc, argv, &function_map);
}
if (!strcmp(argv[1], "selinux_setup")) { // 参数为 "selinux_setup",启动 Selinux 安全策略
return SetupSelinux(argv);
}
if (!strcmp(argv[1], "second_stage")) { // 参数为 "second_stage",启动 init 进程第二阶段
return SecondStageMain(argc, argv);
}
}
// 默认启动 init 进程第一阶段
return FirstStageMain(argc, argv);
}
主要完成以下工作:
- 创建和挂载启动所需的文件目录
- 对属性服务进行初始化
- 设置子进程信号处理函数,如果子进程(zygote进程)异常退出,init进程会调用该函数中设定的信号处理函数来进行处理
- 启动属性服务(其中会启动servicemanager(binder服务大管家)、bootanim(开机动画),mediaserver,surfaceflinger等关键服务)
- 解析init.rc配置文件, 启动zygote服务
参考文章: segmentfault.com/a/119000002… jsonchao.github.io/2019/02/18/…