最近整理了下最新android系统从上电开始的启动流程,这应该是网上最全面的从上电开机到launcher执行的整个启动流程,虽然说还有很多细节没提到,但基本已经是android系统启动的全貌了。

真正想要理解android系统的启动流程需要有一些知识铺垫,包括但不限于操作系统原理、文件系统、密码学、指令集等。

学过操作系统的人都知道x86架构的CPU,它有很多历史包袱,包括实模式到保护模式、段寄存器。这些都是为了兼容老旧cpu而不得不存在。它的指令集比较复杂,一条指令可能包含几条cpu操作,从传统BIOS到现代EFI BIOS依然没有摆脱历史包袱,所以x86系统的启动,最开始必须从16位实模式开始到32位保护模式再到64位长模式层层递进。

而ARM芯片则没有负担,现代ARM自V9.2开始已经不再支持32位指令集,也就是从开机启动cpu处于64位,而arm作为移动端cpu,它不像桌面端cpu那样纯粹,桌面端cpu非常规范,它只要跑计算,不用过多考虑功耗,插在主板上就跑起来了,而移动端芯片功能却要比桌面cpu更多,且功耗要求尽量低,所以很多外设就封装进了芯片内,就变成了SOC,SOC内部包含了gpu、cpu、npu、pmu(电源管理)、音视频编解码器、dsp、通信基带、wifi、蓝牙、gpio、rom、sram等众多模块,这部分芯片厂商会提供BSP板级支持包,包含了集成在SOC内部的BootRom,输入UFS的bootloader以及带有soc内部设备驱动的linux内核、te os安全操作系统,然后提供基础android系统源码,OEM厂商(比如小米)收到芯片厂商的BSP后,在此基础上定制自己的产品,负责编写vendor层的驱动代码,以及定制系统UI和增加新的系统服务或者应用程序,由于谷歌的新架构,分区越来越细,android系统代码不再严重依赖于soc厂商的驱动,因为有兼容性要求,使得小米公司升级上层的android系统代码越来越简单,厂商的代码基本兼容android新系统,所以几乎不需要动,这也就造就了今天android系统的整个组成结构,如下图所示。


AOSP代码,GMS套件-------谷歌

Soc芯片、BSP板级支持包(Bootloader、原始Kernel、TE OS、在AOSP基础上改造的整个系统源码等)---------芯片公司提供(高通、联发科等)

DRAM、UFS选型,基于BSP支持包做特有驱动开发,功能定制---------设备制造商开发(如小米、oppo、vivo等)

上面讲述了android系统的每个部分分别属于产业链的哪个位置,这有助于我们理解为什么android系统会演进到图片上所示的架构。

首先ARM芯片有四种执行状态,分别是(EL0(android用户态),EL1(android内核态),EL2(虚拟化),EL3(安全态)),四种状态可以理解为cpu层级的硬件权限限制,它是系统安全的基石。

下面是对整个启动流程的详细说明。

一、手机开机上电,CPU复位就处于EL3这个安全状态,PC指针直接指向SOC内部的ROM(BootRom),在安全状态下,BootRom可以访问eFuse获取到保存在其中的根公钥,同时BootRom会初始化外部DRAM,使得DRAM可以正常工作。

二、BootRom从UFS磁盘中的固定位置(Boot分区)读取Bootloader Header,从中获取到Bootloader签名信息,使用根公钥解密签名,得到Bootloader的哈希值,然后将Bootloader程序载入非安全内存,并使用哈希算法计算出Bootloader摘要信息,与前面解密出来得到的哈希值做比对,如果不一致,就Boot Failed,引导失败。

三、当哈希比对一致,BootRom就跳转到Bootloader在内存中的位置进行执行,此时CPU还是处于安全模式,Bootloader会从eFuse中获取OEM_UNLOCK_ENABLE标志,该标志决定是否可以解锁Bootloader,使Bootloader可以加载第三方的内核,一般不允许,所以很多手机都是无法解锁Bootloader也就不能刷入第三方的内核镜像,如果允许,Bootloader会读取misc分区的,是否已解锁标志,该标志就是通过fastboot unlock写入,一旦允许,bootloader将不在对后面的内核镜像做验签操作。

四、假设没有解锁,就是正常流程,Bootloader使用代码中内置的公钥去验证vbmeta分区签名信息,验证通过后再次验证vbmeta分区中存储的其他分区的签名信息。

五、验证全部通过后先将TZ这个安全系统载入到DRAM中的安全内存中,CPU执行TZ系统,此时还是安全状态,TZ安全系统会从efuse中获取密钥种子形成密钥保存在安全内存中,同时可能会读取ufs的RPMB分区来获取一些安全信息,然后执行TZ系统的用户态程序。

六、Bootloader还负责读取modem分区的基带固件,将固件载入基带芯片的SRAM中,基带系统在基带芯片中执行。

七、接着Bootloader读取dtbo分区,形成设备树,然后载入kernel进DRAM的非安全内存,将内核启动参数和dtb设备树传入kernel执行kernel代码,此时cpu状态已经切换为EL1内核态,kernel代码分为头部未压缩的代码和后面被压缩的kernel代码,先被执行的是kernel未被压缩的代码,然后在这部分代码中执行对后面压缩kernel的解压然后自运行。

八、kernel执行后,先初始化内存管理模块,中断向量、内核调度器,还有进程管理模块,核心驱动的初始化,接着文件系统初始化,加载网络、GPU、音视频驱动等,完成上述操作后,kernel读取boot_init和vendor_init分区,将分区合并最终挂载成根文件系统,执行它其中的init程序,此时CPU状态从EL1转为EL0变成普通用户态。

九、init进程启动后,它会加载meta分区表信息,验证各个文件系统分区的完整性,防篡改,由于内核已经完成了内存、文件系统初始化,这个时候已经具备了加载文件系统(ext4等)的能力,进程会通过syscall 会先后挂载其他剩余分区(userdata、cache、system、vendor、product等等),初始化各分区中的selinux文件,内核的seliunx模块运作开始运作。

十、接着init会执行init.rc文件,在init.rc中配置的服务进程全部都会fork出来并启动,其中就包含zygote进程,surfaceflinger,service_manager,mediaserver,audioserver,audioflinger等进程,各种hal驱动服务进程等,接着最核心的system_server进程启动,其中就涵盖了android系统中最核心的AMS,PMS,WMS等核心服务,AMS拉起SystemUI、Launcher进程,自此进入了android桌面环境,整个系统启动过程结束。

补充知识:

我们所有的代码无论引导还是操作系统都存放在UFS磁盘中,CPU要执行,必须将UFS中 的代码载入内存,然后跳转执行,载入过程需要读去UFS的扇区,UFS设计了Boot Lun(相当于Boot分区),bootloader以二进制形式存放在其中,RPMB Lun(RPMB分区)存放安全密钥必须cpu安全模式才能读写,User Lun(用户分区) 这部分才是通过GPT分区表来管理的,其中kernel、tz、misc、recovery、misc、dtbo、modem、pvmfw基本都是以二进制形式存放在对应的gpt分区中,不存在文件系统的概念,而其他分区是在内核启动后,文件系统驱动执行后才能挂载,因为其他分区都是以文件系统的形式刷入对应的分区,所以在启动的android系统中你看不到这些二进制形式刷入的分区,因为它们不是文件系统,无法以文件系统的形式挂载到linux文件树中。

One thought on “Android 最新最全面启动流程分析(含 TEE、安全验证等)”

回复 彻底搞懂init进程、init.rc(基于android aosp 15) – late哥哥笔记 取消回复

您的邮箱地址不会被公开。 必填项已用 * 标注