Android系统启动流程总览
绪论
Android是基于Linux内核的, 可扩展的智能终端设备. 越来越多的用户使用Android设备, 而移动智能时代已经悄然而至,很多人都感觉这是一个神奇的世界, 对其知之甚少. 就让我们通过本文来揭开Android设备系统启动的神秘面纱,以此来了解这个神秘的世界.
Android系统总览
当电源键按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行,加载引导程序到RAM,然后执行。
引导程序是Android操作系统开始运行前的一个小程序,一般使用bootloader作为引导程序。引导程序分为两个阶段执行:
1)检测外部的RAM以及加载对第二阶段有用的程序。
2)引导程序设置网络,内存等等。
引导程序可以根据配置参数或输入数据进行配置内核,并且进行加载内核。
内核启动时会进行设置缓存,被保护存储器,计划列表,加载驱动。当内核完成系统设置后,它首先在系统文件中寻找init文件,然后启动init进程。
Init进程是Linux起来之后启动的第一个用户进程,android系统就是在这个进程的基础上启动起来的,进程号为1,init进程主要就是挂载文件目录,如sys/,dev/,proc/。另外就是运行init.rc脚本。由于在init.rc中有对启动Zygote的参数配置,所以最终可以将Zygote启动起来。
Zygote是一个孵化器进程,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育fork出来的。在Zygote中进行添加虚拟机参数,并将其启动起来,然后注册JNI函数。在Zygote中进行预加载以及初始化核心类库。最后将SystemServer启动起来。
在SystemServer中进行对各种系统服务对象进行创建,并将创建好的对象,添加进SeviceManager中可以让其他模块通过ServiceManager就可以获得所需要的服务对象。
前面所有事情都完成后,就可以进行启动Launcher了,最终出现系统主界面。
引导程序是Android操作系统开始运行前的一个小程序,一般使用bootloader作为引导程序。引导程序分为两个阶段执行:
1)检测外部的RAM以及加载对第二阶段有用的程序。
2)引导程序设置网络,内存等等。
引导程序可以根据配置参数或输入数据进行配置内核,并且进行加载内核。
内核启动时会进行设置缓存,被保护存储器,计划列表,加载驱动。当内核完成系统设置后,它首先在系统文件中寻找init文件,然后启动init进程。
Init进程是Linux起来之后启动的第一个用户进程,android系统就是在这个进程的基础上启动起来的,进程号为1,init进程主要就是挂载文件目录,如sys/,dev/,proc/。另外就是运行init.rc脚本。由于在init.rc中有对启动Zygote的参数配置,所以最终可以将Zygote启动起来。
Zygote是一个孵化器进程,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育fork出来的。在Zygote中进行添加虚拟机参数,并将其启动起来,然后注册JNI函数。在Zygote中进行预加载以及初始化核心类库。最后将SystemServer启动起来。
在SystemServer中进行对各种系统服务对象进行创建,并将创建好的对象,添加进SeviceManager中可以让其他模块通过ServiceManager就可以获得所需要的服务对象。
前面所有事情都完成后,就可以进行启动Launcher了,最终出现系统主界面。
主要内容
- uboot启动流程
- uboot调试方法
- kernel启动流程
- kernel编译调试方法
- 概述init到启动Launcher过程
uboot启动流程
u-boot启动过程可以分为两个阶段,两个阶段的功能如下:第一阶段的功能
1.硬件设备初始化
2.加载uboot第二阶段代码到RAM空间
3.设置好栈
4.跳转到第二阶段代码入口
第一阶段对应的文件是u-boot64/arch/arm/cpu/Armv7/start.S。u-boot启动第一阶段流程如下:
第二阶段的功能
1.初始化本阶段使用的硬件设备
2.检测系统的内存映射
3.将内核从Flash读取到RAM中
4.为内核设置启动参数
5.调用内核
2.检测系统的内存映射
3.将内核从Flash读取到RAM中
4.为内核设置启动参数
5.调用内核
u-boot第二阶段代码的入口为board_init_r()函数,在u-boot/arch/arm/lib/board.c中定义。U-boot启动第二阶段流程如下:
board_init_r()是第二阶段C语言开始的函数,该函数主要是调用一系列的初始化函数,初始化高速缓存器和本阶段的外围硬件设备。
之后,跳到do_cboot()函数:
之后,跳到do_cboot()函数:
- 判断开机模式
- 进入相应的开机模式
- 点亮屏幕
- 显示厂商开机logo界面
> 将内核映像和跟文件映像从flash上读到SDRAM空间中
> 为内核设置启动参数
> 启动内核
> 为内核设置启动参数
> 启动内核
Uboot调试方法
可以通过仿照uboot中原有log的格式进行添加log调试,通过minicom抓取串口log.
> 使用minicom获取串口log方法:
- >安装:sudo apt-get install minicom
- >配置:sudo minicom -s
- >设置端口:Serial port setup
串口端口号一般为ttyUSB1或者ttyUSB0
设置完成后就可以进入minicom,进行抓取串口log,调试uboot.
设置完成后就可以进入minicom,进行抓取串口log,调试uboot.
启动内核
在U-boot中对内核进行设置启动参数,经过一系列的跳转,最终到了start_kernel()进行启动kernel.代码位置kernel/init/main.c
当以上所有的初始化工作结束后,start_kernel()函数会调用 rest_init()函数来进行最后的初始化,包括启动系统的第一个进程-init进程来结束内核的启动。在rest_init函数中调用kernel_init来进行接下来的初始化.
Kernel编译与调试
编译kernel其实就是编译boot.img, boot.img是由ramdisk.img和kernel打包组成.ramdisk中包含一些对于启动android的很重要的文件,比如内核启动完后,加载的第一个进程init,一些重要的配置文件(如init.rc)等,总之它控制着整个android的启动
> 编译命令:make bootimage
编译完成后可以用fastboot将boot.img烧到手机中:
- adb reboot bootloader
- fastboot flash boot .../boot.img
- fastboot reboot
有时候由于kernel的缓冲buffer不够大, 在开机过程中可能会冲掉一部分kernel log,导致kernel log不全为分析开机耗时问题带来不小的困恼. 所以,我们在调试的时候可以适当的增大kerne buffer size, 在源码根目录执行kuconfig, 显示如下界面:
> 选择General Setup选项
我们就可以选择kernel log buffer size选项, 17为128KB , kernel log buffer最大为21, 所以我们可以将17改为小于等于21的一个数值. 这样就可以输出比较多的kernel log信息.
在内核 printk.h 文件中定义了很多内核打印 Log 的级别和方法,最常用的就是直接使用
printk(“++++++++++++++++++++++++\n”)
使用dump_stack()输出堆栈信息.
printk(“++++++++++++++++++++++++\n”)
使用dump_stack()输出堆栈信息.
启动Init进程
在kernel中启动Init进程完成后,正式进入用户空间init进程也为用户空间的第一个进程,之后会进入system/core/init/init.cpp中的main()函数,首先将在启动kernel过程中创建好的文件系统框架mount到相应目录,之后对init.rc文件进行解析.
启动zygote
- //system/core/rootdir/init.zygote64.rc
- service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
- class main
- socket zygote stream 660 root system
- onrestart write /sys/android_power/request_state wake
- onrestart write /sys/power/state on
- onrestart restart media
- onrestart restart netd
在app_main.cpp的main函数主要通过启动zygote的参数来对虚拟机进行设置.
间接调用AndroidRuntime的start函数
- 启动虚拟机
- 对虚拟机进行一些初始化
- 注册JNI函数
最后调用ZygoteInit的main函数,进入java层.
进入java世界
在java层经过一系列操作最终将launcher启动起来, 我们就可以操作app,尽情的玩耍了。
后续文章中将详细讲解用户空间的调用,以及开机优化的点子。