系列文章索引
之前写了一些源码的解析文章,包括了如何下载和编译源码,init,zygote,systemServer
相关的源码解析
那么我们回过头来看,其实这个流程是不完整的,init进程
是系统中的首个用户进程,是其他进程的祖先进程
那init 进程
由是如何启动的? Linux内核
是如何加载的? 我们其实并没有提及,所以当我们再回过头来梳理整个启动流程的时候,其实还是一头雾水,那么我们到底忽略了什么东西呢?
整体上讲,Linux系统的启动要经过的流程
手机设备跟pc设备有很大的区别,pc设备的启动,在硬件阶段首先要由BIOS进行设备自检,其次进入MBR(Master Boot Record,主引导区),由bootloader引导程序对Linux内核进行加载引导
Linux系统引导
MBR是所有硬盘中第一扇磁盘分区中前512k大小中分出来的一块引导分区,用来存放bootloader引导程序
Linux系统内核主要通过LILO(Linux Loader)和 GRUB (GRand Unified Bootloader ) 来进行加载引导,完成内核的解压和系统初始化(start_kernel),在系统初始化的最后阶段启动init进程,也就是pid为1的进程
移动设备系统引导
从硬件上来说,移动设备并没有传统的硬盘,使用的是NAND FLASH 闪存存储介质,采用的是是emmc(Embedded Multi Media Card)或ufs(unniversal file system)存储器标准接口
不同分区标准的速度对比
我们的通过fastboot对手机进行刷机时,即将我们的系统固件(ROM)写入到存储介质中,写入到对应的分区中(具体写入的分区与具体的分区标准有关),具体的bootloader相关代码见platform/bootable/recovery/ ,这里不做具体分析linux系统内核引导及初始化
bootloader引导完成后,进入linux kernel代码阶段
我们都知道linux内核的入口函数是start_kernel()
,那这个函数又是如何被执行的呢?
之前我们分析过init
进程的相关源码(基于Android10.0.0_r2版本),我们知道它的源码入口是system/core/main.cpp
从代码上我们把linux内核相关源码分为两部分:一部分是汇编代码,另一部分是c语言相关代码
注:此处linux源码分析基于
android-msm-wahoo-4.4-pie-qpr2
汇编部分代码
arch/arm/head.S
ENTRY(stext) ... @ address to jump to after ldr r13, =__mmap_switched 复制代码
arch/arm/head-common.S
__mmap_switched: ... @ linux内核入口 b start_kernel ENDPROC(__mmap_switched) 复制代码
c语言部分代码
init/main.c
//kerel的入口函数 asmlinkage __visible void __init start_kernel(void) { ... rest_init(); ... } //开启init进程 static noinline void __init_refok rest_init(void) { ... //kernel_init函数在kernel线程中运行 kernel_thread(kernel_init, NULL, CLONE_FS); ... } //内核初始化 static int __ref kernel_init(void *unused) { ... //从下面的路径中找到init进程的可执行文件, //并开启用户态的init进程,由内核态进程跳转到用户态进程 if (!try_to_run_init_process("/sbin/init") || !try_to_run_init_process("/etc/init") || !try_to_run_init_process("/bin/init") || !try_to_run_init_process("/bin/sh")) return 0; panic("No working init found. Try passing init= option to kernel. " "See Linux Documentation/init.txt for guidance."); } 复制代码
至此,我们终于进入了用户态的世界,init进程被启动了,Android的系统启动流程,也才刚刚开始
我们的征途,是星辰大海
由于本人水平有限,如有错误,欢迎交流指出
参考文章