Init进程是如何被启动的?-- 再谈Android系统启动流程

3,007 阅读3分钟

前尘篇:系统启动流程回顾

系列文章索引

  1. 源码下载及编译
  2. Android系统启动流程纵览
  3. init进程源码解析
  4. zygote进程源码解析
  5. systemServer源码解析

之前写了一些源码的解析文章,包括了如何下载和编译源码,init,zygote,systemServer相关的源码解析

那么我们回过头来看,其实这个流程是不完整的,init进程是系统中的首个用户进程,是其他进程的祖先进程

init 进程由是如何启动的? Linux内核是如何加载的? 我们其实并没有提及,所以当我们再回过头来梳理整个启动流程的时候,其实还是一头雾水,那么我们到底忽略了什么东西呢?

混沌初开:init进程之前的世界

整体上讲,Linux系统的启动要经过的流程

  • 设备硬启动
  • bootloader系统引导
  • linux内核初始化及系统初始化
  • init进程挂载系统目录,并启动zygote进程
  • zyogte开启systemServer,启动一系列系统服务
android系统启动流程

手机设备跟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的系统启动流程,也才刚刚开始

我们的征途,是星辰大海

写在最后

由于本人水平有限,如有错误,欢迎交流指出

参考文章

  1. www.jianshu.com/p/9f978d57c…
  2. blog.csdn.net/cuijianzhon…
  3. www.wowotech.net/armv8a_arch…