Android系统启动流程介绍
文章目录
概述
本文将介绍Android系统的启动,从上电开始到系统服务启动完成。整个流程的可以简述为如下流程BootLoader->Kernel -> Native-> Framework-> App,简单讲述一下每个阶段,详细的自下而上的流程介绍如下图
接下来介绍一下这些阶段的具体细节
上电->Bootloader
本阶段主要任务:引导芯片从固化在ROM里预设的代码开始执行。它将引导加载程序加载到RAM中并开始执行。
Bootloader->Kernel
Bootloader的主要作用是准备硬件环境,引导Linux Kernel(Linux内核)的启动。
启动过程中,会区分本次要启动的系统是Android系统或Recovery模式还是Fastboot模式,完成引导加载程序后,它将执行跳转到Linux内核
Kernel->init
Android系统底层基于Linux Kernel, Linux内核在Android上启动的方式与在其他系统上类似。它将设置系统运行所需的一切。初始化中断控制器,设置内存保护,缓存和调度。
- 启动swapper进程(pid=0),这是系统初始化过程kernel创建的第一个进程,用于初始化进程管理、内存管理、加载Display、Camera、Binder等驱动
- 启动kthreadd进程,这是Linux系统的内核进程。kthreadd是所有内核进程的鼻祖。
一旦内存管理单元和缓存被初始化,系统将能够使用虚拟内存并启动用户空间进程。 内核将在根文件系统中查找init进程入口(在Android目录的system/core/hw/init下找到),并将其作为初始用户空间进程启动
init
Kerner启动找到init进程后,进程入口为源码init目录下的main.cpp的main(),然后在Selinux.cpp中使用execv启动init进程(旧版本直接调用/system/core/init/Init.cpp的main())。这个init进程是Linux系统中用户空间的第一个进程(pid=1)
selinux.cpp的Setuplinux方法中加载了selinux的策略并启动selinux的强制模式然后启动了init进程。init的二进制文件存放在机器的/system/bin/init
,然后通过execs启动init进程。
代码内容如下:
这里简单介绍一下FirstStageMain方法所做的工作
- 处理init进程挂掉的情况
- 设置用户组,挂载相关系统文件
- 根据/force_debuggable文件来判断是否允许adb root指令
- 找到init的二进制文件目录,通过execv来启动init进程
至此init进程就被启动起来了,接下来看一下SecondStageMain方法
SecondStageMain函数实现是在init.cpp中,由此可知该函数是其实是init.cpp的入口函数,(在Android10之前的版本中,该类的入口函数为main)其中的主要工作是:
- 使用epoll对init子进程的信号进行监听
- 初始化系统属性,使用mmap共享内存
- 开启属性服务,并注册到epoll中
- 加载系统启动脚本"/init.rc"
- 解析启动脚本,启动相关服务
init进程负责的事情主要便是对init.rc这个系统启动脚本文件进行解析下面从这个rc文件分析相关内容与关键系统服务的启动
initrc
init.rc文件内容为
可以看到这个rc文件还引入了其余的rc文件,这里介绍其中部分
当需要定制系统时,读取ro.hardware属性对应的rc文件,启动相关定制系统服务,每个项目定制的rc文件一般存放在${AndroidSourcePath}/device
目录下。
关键的rc还有导入的zygote的rc文件,然后启动了servicemanager。
init->Zygote
Zygote是一个VM进程,是Java进程的鼻祖, Zygote进程会创建 system_server进程以及各种app进程,它在系统启动时由init进程解析init.rc文件通过app_process启动。import的对应的rc文件是init.zygote64_32.rc
可以看到zygote是通过app_process64来启动的,app_process 调用的命令格式如下
app_process [java-options] cmd-dir start-class-name [options]
可执行文件本身路径 [Java虚拟机参数] 可执行程序所在父目录路径 内部参数
参数三往后:为,有如下四种使用方法
--zygote : 以Zygote模式启动
--start-system-server: 启动SystemServer
--application : 以独立应用程序模式启动(非Zygote模式)
--nice-name:设置新启动的进程名称,
该_app_process64的代码路径与重要调用如下图
根据runtime.start可知最后启动的是com.android.internal.os.ZygoteInit的main
方法,该包名对应的是ZygoteInit.java细节如下
流程:解析rc->调用appprocess->设置进程名称zygote->调用ZygoteInit.java初始化进程->jni调用zygoteInit.cpp完成进程创建->调用runSelectionLoop(),接收其他进程发送的消息创建子进程
Zygote->SytemService
Zygote进程启动后,通过fork的方式启动了SystemServer,简单介绍一下是如何fork SystemServer的
以上就是通过Zygote fork SystemServer的过程,整个流程简述如下
- 解析zygote.rc的相关脚本,获取startSystemserver的属性字段
- 调用startSystemServer()
- 调用forkSystemServer(),为当前进程赋予权限,并设置UID,GID
- 创建ZygoteArgument,调用zygote.forkSystemServer
- JNI调用native的函数,nativeForkSystemServer完成进程的fork工作
在讲解SystemServer前,需要介绍Zygote的另外一个重要功能:启动servicemanager,等介绍完这个Binder大管家后,再回来介绍SystemServer
Init->service_manager
回顾一下上面的init.rc文件
在Zygote启动后,开始启动servicemanager,这里的servicemanager的定义是在Android.bp下
表示servicemanager关联的rc文件是servicemanager.rc,入口是main.cpp
这个servicemanager的rc文件内容如下:
init进程解析rc后会调用serviceManager进程的入口,执行对应的可执行文件:main.cpp的main()方法
上述main代码实现的功能是:
- 打开binder驱动
- 成为context manager
- 开启binder的loop循环,等待客户端发送过来的请求
binder驱动打开后继续向下追踪代码可以得知:
通过mmap(),binder驱动与serviceManager进程建立了映射关系。
本质上就是完成serviceManager进程的虚拟内存空间与内核中binder驱动的物理内存的映射。
具体细节不在本文介绍,至此servicemanager启动完成。继续回到SystemServer继续分析
SystemServer
在上上节已经介绍了Zygote是如何孵化SystemServer的进程,是调用了native层的forkSystemServer()来fork子进程,这也是Zygote fork出的第一个进程。回顾一下ZygoteInit.java的forkSystemServer。
参数args中添加了SystemServer类的全限定名,接下来主要看一下handleSystemServerProcess()看看是如何完成新fork的SystemServer进程剩余工作的并确定如何进入SystemServer的main方法的
经过了上述的过程终于进入了SystemServer的main方法
自此SystemService启动系统服务流程介绍完成。这些服务基本通过
ServiceManager.addService将自身注册进servicemanager统一管理,获取时使用getService获取对应的manager。
这里给出Init启动Zygote到startService的时序图,供参考