基于Android12 分析系统启动过程
本文基于AOSP Android12的源码分析Android系统的启动流程。
由于这部分内容各版本之间差异不大,同样适用于Android12之前的版本。
1. 概述
整体流程为:BootRom > BootLoader > Kernel > init > Zygote > System Server
2. Boot Rom
此步骤称为开机和系统启动。
意味着每当我们按下电源按钮时,BootROM代码就会从预先固定在ROM中的预定位置开始执行,Boot ROM将BootLoader加载到RAM中并开始执行。
3. BootLoader
引导加载程序是一个低级代码,包含指示设备如何启动和查找系统内核的指令。
BootLoader是制造商放置锁和限制的地方,一般解锁才能刷机就是解锁的BootLoader。
引导加载程序是在任何操作系统开始运行之前执行的代码,BooLoader分两个阶段执行:
- 第一阶段,它检测到外部RAM并加载一个在第二阶段有帮助的程序。
- 第二阶段,引导程序会设置需要运行内核的网络,内存等。
4. Kernel
内核启动后,它将启动
- 设置缓存
- 受保护的内存
- 调度
- 加载驱动程序
- 启动内核守护程序
- 安装根文件系统
- 初始化输入/输出
- 启动中断
- 初始化进程表
内核是我们设备中的硬件接口的易于替换的软件最低级别。
当内核首先完成系统设置时,它会在系统文件中寻找init
进程并启动
5. init
init
进程是第一个进程,或者我们可以说它是所有进程的父进程或者父父进程。
init
进程有两个职责:
- 挂载/sys,/dev或/proc之类的目录
- 运行/init.rc脚本。init.rc负责系统的初始化设置
init
进程会设置所有本级服务,这类似于常规的Linux系统引导。
在 init.rc
文件中有如下几行import的rc文件]
import /init.environ.rc
import /system/etc/init/hw/init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /system/etc/init/hw/init.usb.configfs.rc
import /system/etc/init/hw/init.${ro.zygote}.rc
最后一行即为Zygote的启动配置
启动Zygote分为32位和64位,分别对应下面两个rc文件。
system/core/rootdir/init.zygote32.rc
system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
rc配置文件的格式为:service <service_name> <bin_path> <args>
可以发现启动的可执行文件为app_process64
,存放在/system/bin目录下。
5.1 app_process
源码路径:frameworks/base/cmds/app_process/app_main.cpp
app_process
调用的命令格式如下
app_process [java-options] cmd-dir start-class-name [options]
参数一: app_process可执行文件本身路径
参数二: Java虚拟机参数
参数三: app_process可执行程序所在父目录路径,目前未使用
参数三往后:为内部参数,有如下四种使用方法
--zygote
: 以Zygote模式启动
--start-system-server
: 启动SystemServer
--application
: 以独立应用程序模式启动(非Zygote模式)
--nice-name
:设置新启动的进程名称
参考init.zygote64.rc
配置
/system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
5.1.1 main
int main(int argc, char* const argv[])
{
// ...
// AppRuntime继承自AndroidRuntime
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// 忽略第一个参数,命令程序本身
argc--;
argv++;
// ...
int i;
// ...
// 解析运行时参数
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i; // 跳过不使用的parent dir
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME; // zygote 或者 zygote64
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
Vector<String8> args; // 保存参数列表
if (!className.isEmpty()) {
// 以application模式启动
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
// ...
} else {
// 以zygote模式启动
maybeCreateDalvikCache(); // 创建虚Dalvik虚拟机缓存目录
if (startSystemServer) {
args.add(String8("start-system-server"));
}
// 获取abi list
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);
// 在zygote模式中,保存剩于的所有参数供zygote使用
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
if (!niceName.isEmpty()) { // 设置进程名称
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) {
// 根据init.zygote64.rc配置文件可知,zygote为true,执行该条件
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
5.1.2 小结
通过源码分析我们得知app_process主要是解析参数,并确定具体的启动模式(zygote/application),最后由AndroidRuntime负责启动Java虚拟机并调用入口函数执行。
6. Zygote
源码路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
Zygote是一个VM进程,它在系统启动时由init进程解析init.rc文件通过app_process启动。
当app_process启动zygote时,它首先创建Dalvik VM,然后调用ZygoteInit的main方法。
public static void main(String[] argv) {
ZygoteServer zygoteServer = null;
// 标记当前正在启动Zygote,确保线程创建将导致异常
ZygoteHooks.startZygoteNoThreadCreation();
// 使Zygote进入它自己的进程组
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
Runnable caller;
try {
// 存储现在启动相关信息,便于后续使用
final long startTime = SystemClock.elapsedRealtime(); // 记录启动时间
final boolean isRuntimeRestarted = "1".equals(SystemProperties.get("sys.boot_completed"));// 是否重启
String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing"; // Log TAG
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK); // trace记录
bootTimingsTraceLog.traceBegin("ZygoteInit");
// 启用DDMS,设置MimeMap
RuntimeInit.preForkInit();
boolean startSystemServer = false; // 是否需要启动SystemServer
String zygoteSocketName = "zygote"; // 套接字名称
String abiList = null; // abi列表
boolean enableLazyPreload = false; // 是否启用懒加载资源
for (int i = 1; i < argv.length; i++) {
// 参数解析
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
// PRIMARY_SOCKET_NAME = “zygote”
// 标记是否是主要的Zygote
final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
if (!isRuntimeRestarted) {
if (isPrimaryZygote) {
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__Z