本文介绍android的启动流程。
系统启动架构图:
一、Loader层
1. Boot ROM:
上电后,BootRom会被激活,引导芯片代码
开始从预定义的地方(固化在ROM)开始执行,然后加载引导程序到RAM
。
2. Boot Loader引导程序
Boot Loader是启动Android系统之前的引导程序,引导程序是OEM厂商或者运营商加锁和限制的地方,它是针对特定的主板与芯片的。OEM厂商要么使用很受欢迎的引导程序比如redboot
、uboot
、ARMboot
等或者开发自己的引导程序,它不是Android操作系统的一部分。
Boot Loader主要作用是检查RAM,初始化硬件参数等功能。
3 Preloader:
(1)Preloader是MTK平台独有的防止芯片被Hack的一个loader,MTK平台的bootrom会先加载preloader到SRAM中,preloader会先去初始化一些HW组件,比如通信端口(USB/Uart),外部存储设备(Emmc or Nand),内存设备(DRAM Calibration)等,最后会Load LK到DRAM中并且run LK(U-boot)。
(2)LK会从外部存储设备load boot image,包括Linux kernel和Ramdisk到DRAM中.最后LK会跳到 Linux Kernel里去执行start kernel.
(3)linux kernel会先完成一些初始化动作,mount 根文件系统和启动第一个用户进程(init 进程)
二、kernel层
Android内核与linux内核启动的方式差不多。Kernel的启动流程:
alps/kernel/init/main.c
start_kernel() ==> rest_init() ==> kernel_thread(kernel_init) ==> kernel_init()
2.1 rest_init()
|
|
- rest_init中调用kernel_thread函数启动了2个内核线程,分别是:kernel_init和kthreadd
- 调用schedule函数开启了内核的调度系统,从此linux系统开始转起来了。
- rest_init最终调用cpu_idle函数结束了整个内核的启动。
也就是说linux内核最终结束了一个函数cpu_idle。这个函数里面肯定是死循环。 - 简单来说,linux内核最终的状态是:有事干的时候去执行有意义的工作(执行各个进程任务),实在没活干的时候就去死循环(实际上死循环也可以看成是一个任务)。
- 之前已经启动了内核调度系统,调度系统会负责考评系统中所有的进程,这些进程里面只有有哪个需要被运行,调度系统就会终止cpu_idle死循环进程(空闲进程)转而去执行有意义的干活的进程。这样操作系统就转起来了。
0号进程:
swapper进程(pid=0):又称为idle进程, 叫空闲进程,由系统自动创建, 运行在内核态。
系统初始化过程Kernel由无到有开创的第一个进程, 也是唯一一个没有通过fork或者kernel_thread产生的进程。
swapper进程用于初始化进程管理、内存管理,加载Display,Camera Driver,Binder Driver等相关工作。
1号进程
init进程(pid=1):由0号进程通过kernel_thread创建,在内核空间完成初始化后, 加载init程序, 并最终运行在用户空间,init进程是所有用户进程的鼻祖
。
2号进程
kthreadd进程(pid=2):由0号进程通过kernel_thread创建,是Linux系统的内核进程,会创建内核工作线程kworkder,软中断线程ksoftirqd,thermal等内核守护进程。
kthreadd运行在内核空间, 负责所有内核线程的调度和管理 , kthreadd进程是所有内核进程的鼻祖
。
2.2 kernel_init()
init进程会通过kernel_init创建,这个时候是在内核态,那么怎么一步步走到用户态呢?
kernel_init->init_post->run_init_process->kernel_execve
|
|
接下来定位到init_post
的函数体,代码如下:
|
|
execute_command 是bootloader传递给内核的参数,一般是/init(即根目录下的init程序),也就是调用文件系统里的init进程。如果找不到就会继续寻找“/sbin/init”、“/etc/init”、“/bin/init”、“/bin/sh”,找到后便执行run_init_process,且不再返回。run_init_process的函数体非常简单,仅仅是对kernel_execve函数的封装,代码如下:
|
|
kernel_execve
是Linux内核中创建用户进程的方法接口,其实现位于
arch/arm/kernel/sys_arm.c。
那么至此,我们已经对Android Kernel如何引导以及用户空间1号进程(init进程)如何启动做了详细分析。
三、Init进程
3.1 Init Process
这里的Native层主要说明init进程,当kernel Initialize完成之后,系统会执行第一个用户进程init
,我们可以说它是root进程或者所有进程的父进程。init进程相关的代码:
/system/core/init/init.cpp:
/system/core/rootdir/init.rc
/system/core/init/readme.txt
Init进程启动过程就是代码init.cpp中main函数执行过程,我们来看看它做了什么:
|
|
可以看到,init进程主要以下功能:
- 是挂载tmpfs, devpts, proc, sysfs
文件系统
。 - 是运行init.rc脚本,init将会解析init.rc,并且执行init.rc中的命令。
- 当一些关键进程死亡时,重启该进程;
- 提供Android系统的属性服务
3.2 文件系统简介
1. tmpfs文件系统
tmpfs是一种虚拟内存文件系统,因此它会将所有的文件存储在虚拟内存中,并且tmpfs下的所有内容均为临时性的内容,如果你将tmpfs文件系统卸载后,那么其下的所有的内容将不复存在。tmpfs是一个独立的文件系统,不是块设备,只要挂接,立即就可以使用。
2. devpts文件系统
devpts文件系统为伪终端提供了一个标准接口,它的标准挂接点是/dev/pts。只要pty的主复合设备/dev/ptmx被打开,就会在/dev/pts下动态的创建一个新的pty设备文件。
3. proc文件系统
proc文件系统是一个非常重要的虚拟文件系统,它可以看作是内核内部数据结构的接口,通过它我们可以获得系统的信息,同时也能够在运行时修改特定的内核参数。
4. sysfs文件系统
与proc文件系统类似,sysfs文件系统也是一个不占有任何磁盘空间的虚拟文件系统。它通常被挂接在/sys目录下。sysfs文件系统是Linux2.6内核引入的,它把连接在系统上的设备和总线组织成为一个分级的文件,使得它们可以在用户空间存取。
四、init rc文件和语法
init rc文件语法是以行尾单位,以空格间隔的语法,以#开始代表注释行。rc文件主要包含Action
、Service
、Command
、Options
,其中对于Action和Service的名称都是唯一的,对于重复的命名视为无效。
4.1 动作Action
Action: 通过trigger,即以 on开头的语句,决定何时执行相应的service。
- on early-init; 在初始化早期阶段触发;
- on init; 在初始化阶段触发;
- on late-init; 在初始化晚期阶段触发;
- on boot/charger: 当系统启动/充电时触发,还包含其他情况,此处不一一列举;
- on property:
= : 当属性值满足条件时触发;
4.2 服务Service
服务Service,以service开头,由init进程启动,一般运行于另外一个init的子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service,在启动时会通过fork方式生成子进程。
例如: service servicemanager /system/bin/servicemanager
代表的是服务名为servicemanager,服务的路径,也就是服务执行操作时运行/system/bin/servicemanager。
4.3 命令Command
下面列举常用的命令
- class_start
: 启动属于同一个class的所有服务; - start
: 启动指定的服务,若已启动则跳过; - stop
: 停止正在运行的服务 - setprop
:设置属性值 - mkdir
:创建指定目录 - symlink
: 创建连接到 的 符号链接; - write
: 向文件path中写入字符串; - exec: fork并执行,会阻塞init进程直到程序完毕;
- exprot
:设定环境变量; - loglevel
:设置log级别
4.4 可选操作Options
Options是Services的可选项,与service配合使用
- disabled: 不随class自动启动,只有根据service名才启动;
- oneshot: service退出后不再重启;
- user/group: 设置执行服务的用户/用户组,默认都是root;
- class:设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default;
- onrestart:当服务重启时执行相应命令;
- socket: 创建名为/dev/socket/
的socket - critical: 在规定时间内该service不断重启,则系统会重启并进入恢复模式
*default: 意味着disabled=false,oneshot=false,critical=false。
所有的Service里面只有servicemanager ,zygote ,surfaceflinger这3个service有onrestart关键字来触发其他service启动过程。
五、Daemon守护进程
init.rc会启动一些daemon进程,比如ueventd, adbd, servicemanager, vold, netd, debuggerd等。
|
|
六、ServiceManager
ServiceManager也是守护进程,它是android的服务大管家,是一个很重要的服务:
|
|
service servicemanager /system/bin/servicemanager
表示服务名为servicemanager,服务运行的时候会执行/system/bin/servicemanager
。
七、Zygote
Zygote是第一个Java进程,并且是所有java进程的父进程。在init.zygote32.rc文件中,zygote服务定义如下:
|
|
Zygote入口和相关类:
/frameworks/base/cmds/app_process/App_main.cpp (内含AppRuntime类)
/frameworks/base/core/jni/AndroidRuntime.cpp
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/frameworks/base/core/java/com/android/internal/os/Zygote.java
/frameworks/base/core/java/android/net/LocalServerSocket.java
/system/core/libutils/Threads.cpp
解释下第一行参数:
- zygote : 服务名
- systen/bin/app_process : zygote所对应的可执行文件是,通过调用pid =fork()创建子进程
- 剩下的四个参数是zygote进程的
启动参数
,其中最后一个参数--start-system-server
是表示zygote进程启动完成后,马上将system进程启动起来。
zygote启动过程调用堆栈:
|
|
zygote进程的主要工作如下:
- 解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法;
- 调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数;
- 通过JNI方式调用ZygoteInit.main(),第一次进入Java世界;
- registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求;
- preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高ap启动效率;
- zygote完毕大部分工作,接下来再通过startSystemServer(),fork得力帮手system_server进程,也是上层framework的运行载体。
- zygote功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。
八、system_server
上面提到Zygote启动过程中会调用startSystemServer(),可知startSystemServer()函数是system_server启动流程的起点, system_server相关类函数如下:
/frameworks/base/core/java/android/app/ActivityThread.java
/frameworks/base/core/java/android/app/LoadedApk.java
/frameworks/base/core/java/android/app/ContextImpl.java
/frameworks/base/core/java/com/android/server/LocalServices.java
/frameworks/base/services/java/com/android/server/SystemServer.java
/frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
/frameworks/base/services/core/java/com/android/server/ServiceThread.java
/frameworks/base/services/core/java/com/android/server/pm/Installer.java
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
启动流程图如下:
进入到SystemServer.main后,调用堆栈如下:
有兴趣的读者可以跟着follow源码一步步展开,由于篇幅所限,只做总结归纳,system_server最主要的工作就是启动系统服务。 通过startBootstrapServices(), startCoreServices(), startOtherServices()3个方法。
8.1 startBootstrapServices();
[ SystemServer.java ] 启动引导服务
|
|
该方法所创建的服务:ActivityManagerService
, PowerManagerService
, LightsService
, DisplayManagerService
, PackageManagerService
, UserManagerService
, SensorService
服务。
8.2 startCoreServices();
[ SystemServer.java ] 启动核心服务
|
|
启动服务BatteryService
,UsageStatsService
,WebViewUpdateService
。
8.3 startOtherServices()
[ SystemServer.java ] 启动其他服务
该方法比较长,有近千行代码,逻辑很简单,主要是启动一系列的服务:
|
|
其中AMS.systemReady()的大致过程如下:
|
|
ActivityManagerService的systemReady方法,在该方法里会启动系统界面以及Home程序。