最近一时兴起,想对Android的启动流程进行一次分析,经过一番整理,从以下几个方面进行总结,代码部分只讨论思路,不论细节。
Android架构介绍
Android启动概述
BootLoader介绍
Kernel初始化介绍
Init初始化介绍
Zygote启动介绍
SystemServer启动介绍
Launcher启动介绍
Log抓取与分析方法
由于发表文章的时候提示内容过长无法发布,于是把文章拆成了三部分发布:
1. Android架构介绍
Android的架构可以从架构图得知,主要分四层:
Android经典的四层架构图
Android架构图
每一层的作用不做介绍,这里主要讲涉及的镜像有boot.img、system.img、vendor.img、recovery.img、userdata.img、cache.img,与平台相关的镜像有lk.bin(MTK)、preloader.img(MTK)、logo.bin(MTK)、emmc_appsboot.mbn(QCOM)、splash.img(QCOM)等,通常来说,修改kernel层通常编译boot.img即可,修改Framework层或Native层主要是编译system.img,在Android O之后修改某些模块还需要编译vendor.img,主要是受Android O Treble的影响,具体问题需要具体分析。
2. Android启动概述
概述:Loader > Kernel > Native > Framework > Application
细分:BootRom > Bootloader > Kernel > Init > Zygote > SystemServer > Launcher
Loader层主要包括Boot Rom和Boot Loader
Kernel层主要是Android内核层
Native层主要是包括init进程以及其fork出来的用户空间的守护进程、HAL层、开机动画等
Framework层主要是AMS和PMS等Service的初始化
Application层主要指SystemUI、Launcher的启动
3. BootLoader介绍
Bootloader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。
调用流程:
crt0.S > kmain > arch_init > target_init > apps_init > aboot_init
3.1 crt0.S
高通平台:alps/bootable/bootloader/lk/arch/{paltform}/crt0.S
MTK平台:alps/vendor/mediatek/proprietary/bootable/bootloader/lk/arch/{paltform}/crt0.S
platform主要有arm、arm64、x86、x86-64等,crt0.S代码大体如下,在_start中先主要完成CPU初始化,禁用mmu,禁用cache,初始化异常向量表等操作,最后将直接跳转到函数kmain中
.section ".text.boot"
.globl _start
_start:
b reset
b arm_undefined
b arm_syscall
b arm_prefetch_abort
b arm_data_abort
b arm_reserved
b arm_irq
b arm_fiq
/*pre-loader to uboot argument Location*/
.global BOOT_ARGUMENT_LOCATION
BOOT_ARGUMENT_LOCATION:
.word 0x00000000
...
#if (!ENABLE_NANDWRITE)
#if WITH_CPU_WARM_BOOT
ldr r0, warm_boot_tag
cmp r0, #1
/* if set, warm boot */
ldreq pc, =BASE_ADDR
mov r0, #1
str r0, warm_boot_tag
#endif
#endif
...
#if defined(ARM_CPU_CORTEX_A8) || defined(ARM_CPU_CORTEX_A9)
DSB
ISB
#endif
bl kmain
b .
3.2 kmain
高通平台:alps/bootable/bootloader/lk/kernel/main.c
MTK平台:alps/vendor/mediatek/proprietary/bootable/bootloader/lk/kernel/main.c
/* called from crt0.S */
void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;
void kmain(void)
{
#if !defined(MACH_FPGA) && !defined(SB_LK_BRINGUP)
boot_time = get_timer(0);
#endif
// get us into some sort of thread context
thread_init_early();
// early arch stuff
arch_early_init();
// do any super early platform initialization
platform_early_init();
#if defined(MACH_FPGA) || defined(SB_LK_BRINGUP)
boot_time = get_timer(0);
#endif
// do any super early target initialization
target_early_init();
dprintf(INFO, "welcome to lk\n\n");
// deal with any static constructors
dprintf(SPEW, "calling constructors\n");
call_constructors();
// bring up the kernel heap
dprintf(SPEW, "initializing heap\n");
heap_init();
// initialize the threading system
dprintf(SPEW, "initializing threads\n");
thread_init();
// initialize the dpc system
dprintf(SPEW, "initializing dpc\n");
dpc_init();
// initialize kernel timers
dprintf(SPEW, "initializing timers\n");
timer_init();
#ifdef MTK_LK_IRRX_SUPPORT
mtk_ir_init(0);
#endif
#if (!ENABLE_NANDWRITE)
// create a thread to complete system initialization
dprintf(SPEW, "creating bootstrap completion thread\n");
thread_t *thread_bs2 = thread_create("bootstrap2", &bootstrap2, NULL,
DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
if (thread_bs2)
thread_resume(thread_bs2);
else {
dprintf(CRITICAL, "Error: Cannot create bootstrap2 thread!\n");
assert(0);
}
thread_t *thread_io = thread_create("iothread", &iothread, NULL,
IO_THREAD_PRIORITY, DEFAULT_STACK_SIZE);
if (thread_io)
thread_resume(thread_io);
else {
dprintf(CRITICAL, "Error: Cannot create I/O thread!\n");
assert(0);
}
// enable interrupts
exit_critical_section();
// become the idle thread
thread_become_idle();
#else
bootstrap_nandwrite();
#endif
}
kmain主要流程:
调用thread_init_early初始化线程系统
调用arch_early_init中判断如果存在mmu就初始化,设置异常向量基地址,使能中断相关寄存器
在platform_early_init中完成初始化硬件时钟、手机的主板等操作,这个函数每种cpu的实现都不一样,定义在bootable\bootloader\lk\platform{cpu型号}\platform.c下
target_early_init中完成初始化uart端口的操作,这个函数的实现在bootable\bootloader\lk\target{cpu型号}\init.c
调用函数heap_init完成内核堆栈的初始化,用与kmalloc等函数的内存分配
在thread_init函数中初始化定时器
调用timer_init初始化内核定时器
如果没有定义ENABLE_NANDWRITE,就创建出一个名为bootstrap2的线程,然后运行这个线程。退出临界区,开中断;如果定义了ENABLE_NAND