Android系统启动流程
先看一张图,从Android系统设备开机到Zygote进程启动,经历了一下几个过程。
- init进程
init进程是linux的根进程,android系统是基于linux系统的,因此可以算作是整个android操作系统的第一个进程;Linux中的所有进程都是有init进程创建并运行的。首先Linux内核启动,然后在用户空间中启动init进程,再启动其他系统进程。在系统启动完成完成后,init将变为守护进程监视系统其他进程。
具体启动流程文章:
https://blog.csdn.net/wjky2014/article/details/103143700
https://www.jianshu.com/p/657336b545bd
什么是Zygote进程
Zygote(孵化)进程是所有android进程的父进程,包括SystemServer和各种应用进程都是通过Zygote进程fork出来的。Zygote进程相当于是android系统的根进程,后面所有的进程都是通过这个进程fork出来的,创建Zygote进程的时候主要做了下面几件事:
- 创建JVM
- 启动SystemServer进程
- 孵化应用进程
由于Zygote进程在启动时会创建JVM,因此通过fock而创建的应用程序进程和SystemServer进程可以在内部获取一个JVM的实例拷贝。
Zygote启动流程
一、init
进程加载init.rc
,引入zygote.rc
1、Zygote进程是由init进程孵化出来的,init进程启动的时候会去加载init.rc
配置文件,文件地址是:/system/core/rootdir/init.rc
。配置文件中又加载了zygote.rc,源码如下:
import /init.${ro.zygote}.rc
zygote,rc文件又分为32位和64位的配置,如下所示:
这代表了Andorid系统支持4种运行模式:
-
纯32位模式:属性ro.zygote的值为zygote32
-
混32位模式(即32位为主,64位为辅)模式:属性ro.zygote的值为zygote32_64
-
纯64位模式:属性ro.zygote的值为zygote64
-
混64位模式(即 64位为主,32位为辅)模式:属性ro.zygote值为zygote64_32
init进程会根据设备的不同来加载不同的zygote配置文件。zygote.rc
配置文件如下所示:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
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
使用的是Android init配置脚本的语法,重点关注第一行内容:service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
zygote
是启动service的名称/system/bin/app_process64
是编译完成后的可执行文件路径--zygote --start-system-server --socket-name=zygote
是启动参数
zygote进程是通过fork创建的,然后执行execve()函数来启动进程,execve()函数需要传入一个可执行文件路径和创建参数,传入的就是这个地方配置的。execve()函数叫做执行程序函数,可以来执行shell脚本,单独的shell命令,或者是调用其他的程序。
2、 init.cpp分析
init.cpp
程序是init进程启动程序,文件路径是/system/core/init/init.cpp
。在main入口函数中,主要做了以下几件事:
- ueventd和watchdogd守护进程
- 创建目录,挂载分区
- 解析启动脚本
- 启动服务
- 守护服务
3、 fork zygote进程
- 在main函数中调用
selinux_initialize
初始化方法 - 在
selinux_initialize
方法中调用selinux_load_policy
方法 - 在
selinux_load_policy
方法中调用selinux_load_split_policy
方法 - 调用
fork_execve_and_wait_for_completion
方法 - 在
fork_execve_and_wait_for_completion
方法中fork子进程,当fork完进程时,如果返回0表示是子进程,如果返回子进程pid则是父进程。zygote进程就在这里被创建。 - 最后通过
execve
函数来执行编译好的可执行文件,来启动zygote进程。,exec将用一个新的可执行文件的内容替换当前进程的代码段、数据段、堆和栈段。Fork加exec 是Linux启动应用的标准做法,init进程也是这样来启动的各种服务的。 - Zygote初始化时会创建创建虚拟机,同时把需要的系统类库和资源文件加载到内存里面。Zygote fork出子进程后,这个子进程也继承了能正常工作的虚拟机和各类系统资源,接下来子进程只需要装载APK文件的字节码文件就可以运行了。
二、app_main.cpp类中调用
app_main.cpp
类文件路径在:/frameworks/base/cmds/app_process/app_main.cpp
1、 在类中,下面代码 判断参数是不是--zygote
,这个参数就是解析的zygote.rc
配置文件中的参数
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote
--start-system-server --socket-name=zygote
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} 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;
}
}
2、 如果是zygote,则通过AppRuntime来调用ZygoteInit
类
if (zygote) {
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.");
}
3、 AppRuntime类的实现在app_main.cpp类中
通过对main()函数的分析,可以看出main()主要根据传入的参数初始化启动参数,具体的启动过程是由AppRuntime完成的。AppRuntime的声明和实现都在app_main.cpp中,它继承自AndroidRuntime,start是AndroidRuntime中的方法。
start函数主要作用是:
- 启动Android运行时环境,
- 启动虚拟机
- 调用className参数所指定的类的main()方法(即:Java中的main方法)。传的是
com.android.internal.os.ZygoteInit
,所以调用的是ZygoteInit.java类的main方法
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
// 代码省略。。。。
// 1、启动Java虚拟机
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
// 2、注册Android JNI函数
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
// 3、调用ZygoteInit类中的main()方法
jmethodID startMeth =