一.Android 系统架构图
虽然 Android 系统非常庞大且错综复杂,但整体架构设计清晰。Android 底层内核空间以 Linux Kernel 作为基石,上层用户空间由 Native系统库、虚拟机运行环境、框架层组成,通过系统调用(Syscall)连通系统的内核空间 与 用户空间。对于用户空间主要采用 C++ 和 Java 代码编写,通过 JNI 技术打通用户空间的 Java层 和 Native层(C++/C),从而连通整个系统。为了能让大家整体上大致了解Android系统涉及的知识层面,先来看一张Google官方提供的经典分层架构图:
Linux内核层
Android系统是基于Linux操作系统的,严格来说,它属于Linux操作系统的一个变种。
好处:
避免了与硬件直接打交道;基于Linux系统的驱动开发可扩展性很强;
硬件抽象层
通过定义硬件“驱动”的接口来进一步降低Android系统与硬件的耦合度;
由于Linux遵循的是GPL协议,而Android开源项目基于Apache协议,意味着其下的所有驱动都应该开源,
这一点对于部分厂商来说无法接受;
系统运行库
这层中包含了支持整个系统正常运行的基础库,由于这些库多数都由C/C++实现,因此也被一些开发人员
成为“C库层”,以区别于应用程序框架层。
应用程序框架层
与系统运行库被称为“C库层”相对应,应用程序框架层往往被冠以“JAVA库”的称号。这是因为框架层
所提供的组件一般都是以JAVA语言编写而成,他一方面为上层应用程序提供了API接口;
另一方面也囊括了不少系统级服务进程的实现,是与Android应用程序开发者关系最直接的一层
应用程序层
应用是用java语言编写的运行在虚拟机上的程序,比如Email客户端,SMS短消息程序,日历等
二.Android 启动流程
Android启动流程图:
1.Boot Rom:按电源键上电后,引导芯片从固化在ROM的预设代码开始执行,加载引导程序到RAM中
2.SML:初始化TrustZone TEE运行环境,运行时切换非安全世界(Android/Linux)和安全世界(TOS),支持CPU core power up、power down、suspend和resume等CPU电源管理功能,控制部分芯片安全硬件模块
3.TOS:实现Trusty OS基本模块,包括线程调度、中断处理、MMU、内存子系统、Timer以及系统调用等。完成安全启动、指纹、人脸、安全存储、数据加解密等安全业务
4.Bootloader:引导程序,主要作用是初始化flash、将内核kernel拷贝到内存中、启动内核
5.启动kernel:主要是启动内核线程kernel_init。kernel_init函数完成设备驱动程序的初始化,并调用init_post启动用户空间的init进程
6.启动init进程:在Linux系统中,所有的进程都是由init进程直接或间接fork出来的。init进程负责创建系统中最关键的几个子进程,尤其是zygote进程,另外它还提供了property service。
7.启动surfaceflinger进程:init在解析rc过程中,在boot阶段通过class_start core接口启动surfaceflinger进程。当surfaceflinger启动之后会通过init设置“service.bootanim.exit”属性为0,同时调用ctl.start接口通知init启动bootanimationservices(开机动画显示服务)。
8.启动zygote进程:当init进程创建之后,会fork出一个zygote进程,这个进程是所有Java进程的父进程。
9.启动SystemServer进程:SystemServer进程由zygote进程fork,这个进程在整个Android系统中非常重要,系统里面的服务都是在这个进程里面开启的,例如AMS(Activity Manager Service,活动管理服务)、WindowsManager等。
10.运行Home Activity:最后AMS会通过Home intent启动launcher。
三.Init进程启动过程
init进程是Android系统中用户空间的第一个进程,进程号为1,是Android系统启动流程中的一个关键的步骤,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建Zygote(孵化器)和属性服务等。init进程是由多个源文件共同组成的,这些源文件位于源码目录system/core/init中。
kernel_init初始化如上图:
kernel_init启动后,完成一些init的初始化操作。启动后去系统根目录下依次找ramdisk_execute_command和execute_command设置的应用程序,如果这两个目录都找不到,就依次去根目录下找/sbin/init、/etc/init、/bin/init、/bin/sh,只要这些应用程序有一个启动了,其他就不需启动了。当log中出现以下信息说明init启动成功。
00736 <0> [12.935128][01-01 08:00:11.935] run init
00737 <14> [12.961677][01-01 08:00:11.961] init: init first first stage started!Android系统一般会在根目录下放一个init的可执行文件,也就是说Linux系统的init进程在内核初始化完成后,就会直接执行该init文件。
内核启动init进程
四.zygote启动流程
zygote启动流程
init进程启动后,zygote是最重要的一个进程,它是所有Android Java进程的父进程。SystemServer和其他所有Dalivik虚拟机进程都是由zygotefork而来。
zygote是由app_process启动。zygote按C/S模型工作,它作为服务端,其他进程作为客户端。其他进程向zygote发出fork请求,zygote收到请求后fork一个新的进程。
zygote启动过程
init进程启动后,会解析init.rc文件,然后创建和加载service字段指定的进程。zygote进程就是以这种方式,被init进程加载的。
在/system/core/rootdir/init.rc中,通过如下引用来加载zygote的rc。import /system/etc/init/hw/init.${ro.zygote}.rc其中,${ro.zygote}由各个厂家使用,现在主流厂家基本使用zygote64_32,相应的${ro.zygote}.rc文件为init.zygote64_32.rc。
init.zygote64_32.rc
Primaryzygote
进程名:zygote进程通过/system/bin/app_process64来启动,支持64位程序。
启动参数:-Xzygote/system/bin --zygote--start-system-server --socket-name=zygote
socket名称:zygote
Secondary zygote
进程名:zygote_secondary
进程通过/system/bin/app_process32来启动,支持32位程序。
启动参数:-Xzygote/system/bin --zygote--socket-name=zygote_secondary --enable-lazy-preload
socket名称:zygote_secondary
从init.zygote64_32.rc中的以下内容可以看出,zygote是通过进程文件/system/bin/app_process64和/system/bin/app_process32来启动的。
zygote进程重启
有些services发生异常重启时会同时重启zygote,其对应的rc文件中有“onrestart restart zygote”的字样。以surfaceflingerservice为例,surfaceflinger.rc相关内容如下。
如上述rc文件所示,当surfaceflingerservice发生异常重启时会同时重启zygote。
zygote进程的重启时机如下
zygote的工作内容
zygote是所有Android Java进程的父进程,是Java世界的入口。zygote启动后的工作内容
zygote流程图
startVM()
该函数主要是初始化VM参数。需重点关注dalvik heapsize的初始化,如果VM参数未配置正确或使用默认参数很有可能导致手机无法进入Launcher。目前app占用的heapsize都比较大,使用默认参数很容易出现内存不足,导致应用不断重启。
startReg()
注册JNI(Java Native Interface,Java原生接口)函数,遍历gRegJNI数组中JNI register方法注册JNI method。注册JNI后,会通过JNI调用java class(zygoteInit)的main函数进入java世界。
registerServerSocket()
通过获取环境变量值得到zygote文件描述符,根据该文件描述符创建socket,用来和ActivityManagerService通信。AMS通过Process.start来创建新的进程,而Process.start会先通过socket连接到zygote进程,并最终由zygote完成进程创建。
preload()
预加载类和资源,zygote通过预加载类和资源可以加快子进程的执行速度和优化内存。因为预加载的类和资源较多,在开机优化过程中也需要重点关注preload的耗时。
预加载Class文件路径:/system/etc/preloaded-classes预加载resource文件路径:frameworks/base/core/res/res/values/arrays.xml
forkSystemServer()
启动system_server进程,Android Java系统服务都将驻留在该进程中,是Android framework核心。设置systemserver进程的uid、gid、process name和class name。