安卓系统层次框架图如下
图片清晰地展示了Android的五层架构,从上到下依次是:应用层、应用框架层、库层、HAL层以及Linux内核层。
Android的启动流程是自下向上的,大体上可以分为三个阶段:1、BootLoader引导启动内核;2、启动Linux内核;3、启动Android系统。
Android 启动流程图如下:
1 Boot ROM
我们长按电源按键,引导 ROM 代码从 ROM 中预定义位置开始执行。它将引导加载程序加载到 RAM 中并开始执行。存储在Boot ROM中的 Primary Bootloader (PBL)是引导过程第一阶段,此代码由芯片制造商编写;PBL验证下一阶段的真实性,如果辅助引导加载程序验证失败,则进入EDL(Emergency Download)。
由于Boot ROM 空间有限,因此将辅助引导加载程序存储在eMMC中
2 Bootloader
Bootloader主要是在系统加载前,初始化硬件设备,建立内存空间的映像图,为最终调用系统内核准备好环境。在 Android运行环境中里没有硬盘,而是 ROM,它类似于硬盘存放操作系统,用户程序等。ROM 跟硬盘一样也会划分为不同的区域,用于放置不同的程序
Bootloader程序分两个阶段执行。第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序;第二阶段,设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,bootloader可以根据配置参数或者输入数据设置内核。
3 初始化Kernel
kernel开始启动时,设置缓存、被保护存储器、计划列表,加载驱动。当初始化内核之后,就会启动一个相当重要的祖先进程,也就是init进程,在Android系统中,会有一个init.rc脚本,init进程一旦启动就会读取并解析这个脚本文件,把其中的元素整理成自己的数据结构(链表)。
4 Zygote进程
当init进程创建之后,会fork出一个Zygote进程,这个进程是所有Java进程的父进程。Android是基于Java的(底层也是C),所有这里就会fork出一个Zygote Java进程用来fork出其它的进程。在Zygote开启的时候,会调用ZygoteInit.main()进行初始化。
init.rc 部分解析执行主要代码路径:systemcoreinit
解析流程: main.cpp(SecondStageMain)->init.cpp(LoadBootscripts)->Parser.cpp(ParseConfig)
Action执行流程:main.cpp(SecondStageMain)->->init.cpp(LoadBootscripts)->action_manager.cpp(ExecuteOneCommand)
service 会略微复杂,有兴趣的可以自己去看看。
通过对init.rc的解析,创建了Zygote 系统服务,在初始化时会启动虚拟机,并加载一些系统资源。这样 zygote fork 出子进程后,子进程也继承了能正常工作的虚拟机和各种系统资源,接下来只需装载 apk 文件的字节码就可以运行应用程序了,可以大大缩短应用的启动时间,这就是 zygote 进程的主要作用。
zygote服务的启动是通过init.rc启动服务,执行的是app_process,app_process是由frameworks/base/cmds/app_process/app_main.cpp编译出来的。
#init.rc service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
调用Android start ->startVm函数来创建虚拟机,调用startReg函数为java虚拟机注册JNI方法,通过toSlashClassName找到ZygoteInit,通过GetStaticMethedID函数找到main方法然后调用,ZygoteInit的main方法是由Java语言编写的,当前的运行逻辑在Native中,这就需要JNI来调用Java,这样Zygote就从Native层进入了Java框架层(ZygoteInit)。
在ZygoteInit中创建zygoteServer,为其他进程初始化创建时与zygote通信做准备,
fork出了SystemServer进程
关于Zygote的疑问- 孵化应用进程这种事为什么不交给SystemServer来做,而专门设计一个Zygote?
- 我们知道,应用在启动的时候需要做很多准备工作,包括启动虚拟机,加载各类系统资源等等,这些都是非常耗时的,如果能在zygote里就给这些必要的初始化工作做好,子进程在fork的时候就能直接共享,那么这样的话效率就会非常高。这个就是zygote存在的价值,这一点呢SystemServer是替代不了的,主要是因为SystemServer里跑了一堆系统服务,这些是不能继承到应用进程的。而且我们应用进程在启动的时候,内存空间除了必要的资源外,最好是干干净净的,不要继承一堆乱七八糟的东西。所以呢,不如给SystemServer和应用进程里都要用到的资源抽出来单独放在一个进程里,也就是这的zygote进程,然后zygote进程再分别孵化出SystemServer进程和应用进程。孵化出来之后,SystemServer进程和应用进程就可以各干各的事了
- Zygote的IPC通信机制为什么不采用binder?如果采用binder的话会有什么问题么?
- 第一个原因,我们可以设想一下采用binder调用的话该怎么做,首先zygote要启用binder机制,需要打开binder驱动,获得一个描述符,再通过mmap进行内存映射,还要注册binder线程,这还不够,还要创建一个binder对象注册到serviceManager,另外AMS要向zygote发起创建应用进程请求的话,要先从serviceManager查询zygote的binder对象,然后再发起binder调用,这来来回回好几趟非常繁琐,相比之下,zygote和SystemServer进程本来就是父子关系,对于简单的消息通信,用管道或者socket非常方便省事。第二个原因,如果zygote启用binder机制,再fork出SystemServer,那么SystemServer就会继承了zygote的描述符以及映射的内存,这两个进程在binder驱动层就会共用一套数据结构,这显然是不行的,所以还得先给原来的旧的描述符关掉,再重新启用一遍binder机制,这个就是自找麻烦了。
systemserver 创建:
ZygoteInit.java(main)->forkSystemServer ->Zygote.java(forkSystemServer)->nativeForkSystemServer->com_android_internal_os_Zygote.cpp(com_android_internal_os_Zygote_nativeForkSystemServer)->ForkCommon
5.SystemServer进程创建



