Blog
Blog copied to clipboard
Android 系统启动流程
转载自
枫寒 - 简书,略作修改。本文包含三个部分:综述 Android 系统启动,Android 的 init 进程启动过程,Zygote 的启动过程。
正文
Android 系统启动
对于Android系统整个启动过程来说,基本可以划分成三个阶段:Bootloader 引导、Linux kernel 启动、Android 启动。如下的流程图可以看出三个阶段的执行顺序和联系(一张图看不懂就看三张图)。
Bootloader 引导
BootLoader是在操作系统运行之前运行的一段程序,它可以将系统的软硬件环境带到一个合适状态,为运行操作系统做好准备。它的任务就是把 OS 拉起来运行,启动 Linux 内核,我们对这一块的内容并不太注意。
Linux kernel启动
Linex kernel启动后会初始化环境/驱动等,接着会启动 init的进程。
1.Init进程的启动
init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序 init 的方式,启动 init 进程。
启动过程是代码system\core\init\init.cpp
的 main 函数的执行过程。在函数中执行了:文件夹建立,挂载,rc文件解析,属性设置,启动服务,执行动作,socket 监听等。在rc文件解析中会启动 ServiceManager 服务和 Zygote 进程。
2. ServiceManager 服务
ServiceManager 用来管理系统中所有的 binder service,不管是本地的c++实现的还是java语言实现的都需要这个进程来统一管理,最主要的管理就是,注册添加服务,获取服务。所有的 Service 使用前都必须先在 ServiceManager 中进行注册。
3. Zygote 进程的启动
Zygote 进程启动才算建立起真正的 Android 的运行空间。不过 Init 进程不会直接启动 Zygote 进程,而是使用 app_process 命令来通过 Android Runtime 来启动,Android Runtime 会启动第一个 Davlik 虚拟机,并调用 Zygote 的 main 方法,启动服务。dir/system/core/rootdir/init.zygote32.rc:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
Android启动
1. Zygote 启动
Zygote 从 frameworks/base/cmds/app_process/app_main.cpp 中的 main 开始,并建立 Android Run Time。
//建立 Android runtime
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
// 然后调用 Java 的 ZygoteInit
// dir/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
// 随后
//登记Listen端口
registerZygoteSocket();
//启动SystemServer服务
startSystemServer();
2. SystemServer启动
在上一步中调用了 startSystemServer, Zygote 上 fork 了一个进程:com.android.server.SystemServer。于是 Java 中的 SystemServer 就建立起来了,SystemServer 的 main 函数中会启动一些服务:
startBootstrapServices();
startCoreServices();
startOtherServices();
在startBootstrapServices()中看到
mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();
ActivityManagerService.Lifecycle 是 ActivityManagerService 的静态内部类, 持有 ActivityManagerService 实例。所以 ActivityManagerService 是在这里被启动起来的。
当然还有很多的其他服务(PackageManagerService、PowerManagerService、DisplayManagerService、BatteryService等)也都会被启动起来。
在所有的服务启动完成后,会调用Service.systemReady()来通知各对应的服务,系统已经就绪。
3.ActivityManagerService启动
在 ActivityManagerService 的 systemReady() 方法中有:
startHomeActivityLocked();
mStackSupervisor.startHomeActivity()
这样Home程序被启动起来,整个android的启动过程就完成了,进入用户界面。
Android 的 init 进程启动过程
0. 前言
Android 中的内核启动后,kernel 会启动第一个用户级别的进程:init,它是一个由内核启动的第一个用户级进程。我们可以通过adb shell ps | grep init
来查看到他的 pid 为 1。接下来从源码的角度看看init进程启动的时候做了什么?
init 进程的源码在 android 源码的: dir/system/core/init 目录中。我们看到该目录下有一个 Android.mk 文件,至少看到如下内容,告诉我们会生成一个 init 的的可执行文件。
LOCAL_MODULE:= init
include $(BUILD_EXECUTABLE)
而 init 的入口 main 函数是在 init.cpp 文件中定义的。
1. 入口
1. 命令行解析
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}
watchdog 和 uevent 命令已经集成到了 init, 它们在 /sbin 目录,是一个链接文件,直接链接到 /init,所以当执行 /sbin/eventd 或 /sbin/watchdogd 时,将会进入对应的 ueventd_main 或 watchdogd_main 入口点。ueventd 守护进程负责解析 /ueventd.rc 文件,并创建相应的设备结点等。watchdogd 守护进程负责定时向 "/dev/watchdog" 执行写操作,以判断系统是否正常运行。这两个进程不是本文讨论的重点,所以先忽略。
2. 挂载根文件系统的目录
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
分别挂载 proc 和和 sysfs 文件系统到 /proc 和 /sys 目录 close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000)); 在/dev目录创建一个空文件 .booting 来表示正在执行初始化 InitKernelLogging(argv); 重定向标准输入,标准输出,标准错误输出到 /dev/null selinux_initialize(is_first_stage) 加载SELinux策略, 后面有一些初始化文件上下文的操作等
3. 解析 init.rc 文件
Parser& parser Parser::GetInstance();
parser.AddSectionParser("service",std::make_unique<ServiceParser>());
parser.AddSectionParser("on", std::make_unique<ActionParser>());
parser.AddSectionParser("import", std::make_unique<ImportParser>());
parser.ParseConfig("/init.rc");
-
3.1 init.rc 文件是以块(section)为单位组织的,一个 section 包含多行。section 分为两大类:分别为“服务(service)”和“行为(action)”。
-
3.2 “服务”块以关键字“service”开始,表示启动某个进程的方式和参数,“行为”块以关键字“on”开始,表示一堆命令的集合。每个块以关键字“service”或“on”开始,直到下一个“on”或“service”结束,中间所有行都属于这个“块”。
-
3.3 上面在解析 init.rc 文件时使用了 Parser 类(在init目录下的init_parser.h中定义), 初始化 ServiceParser 用来解析 “service”块,ActionParser 用来解析"on"块,ImportParser 用来解析“import”块,“import”是用来引入一个 init 配置文件,来扩展当前配置的。
-
3.4 parser 解析 init.rc 文件,/init.rc 文件是 dir/system/core/rootdir/init.rc。
-
3.5 dir/system/core/init/readme.txt 中对 init 文件中的所有关键字做了介绍,主要包含了 Actions, Commands, Services, Options, and Imports 等
-
3.6 在 ParseConfig 解析完 init 脚本后,init会依次执行几个重要的阶段:
3.6.1 on early-init阶段
am.QueueEventTrigger("early-init"); 执行 on early-init 内容,主要包括 start ueventd 等
3.6.2. on init 阶段
am.QueueEventTrigger("init"); 执行 on init 内容,主要包括 创建/挂载一些目录,以及 symlink 等
3.6.3. on charger/late-init阶段
``` // Don't mount filesystems or start core system services in charger mode. std::string bootmode = property_get("ro.bootmode"); if (bootmode == "charger") { am.QueueEventTrigger("charger"); } else { am.QueueEventTrigger("late-init"); } ```
如果是充电模式下启动 就会执行 on charger 内容, 否则执行 on late-init 内容,在 init.rc 的 on late-init 中看到很多 trigger(触发器),用于执行对应的 Action。
``` trigger late-fs # Now we can mount /data. File encryption requires keymaster to decrypt # /data, which in turn can only be loaded when system properties are present. trigger post-fs-data # Load persist properties and override properties (if enabled) from /data. trigger load_persist_props_action # Remove a file to wake up anything waiting for firmware. trigger firmware_mounts_complete trigger early-boot trigger boot ```
从最后两行可以看出,late-init 触发了on early-boot 和 on boot 两个 Action。
3.6.4. on boot 阶段在 on boot 的最后 class_start core 会启动 class 为核心的服务,这些服务包括 ueventd、logd、healthd、adbd(disabled)、lmkd(LowMemoryKiller)、servicemanager、vold、debuggerd、surfaceflinger、bootanim(disabled)等
3.6.5. main 服务的启动
在 main 函数后面的 while 循环中,调用 execute_one_command 依次执行操作队列中的命令
``` while (true) { if (!waiting_for_exec) { am.ExecuteOneCommand(); restart_processes(); } } ```
在 /init.rc 的开头部分
``` import /init.environ.rc import /init.usb.rc import /init.${ro.hardware}.rc import /init.usb.configfs.rc import /init.${ro.zygote}.rc ```
通过 ro.zygote 的属性 import 对应的 zygote 的 rc 文件,通过 adb shell getprop ro.zygote 查看得到 zygote64_32, 所以 import 的是 /init.zygote64_32.rc 文件,该文件中定义的 zygote 如下:
``` service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote class main priority -20 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 writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks ```
可以看到 zygote 的 class 是 main, 它是在 on nonencrypted 时被启动的
``` on nonencrypted # A/B update verifier that marks a successful boot. exec - root -- /system/bin/update_verifier nonencrypted class_start main class_start late_start ```
注:但在 Android 7.0 中,对该机制做了一些改变 。 单一的init*.rc,被拆分,服务根据其二进制文件的位置(/system,/vendor,/odm)定义到对应分区的etc/init目录中,每个服务一个 rc 文件。与该服务相关的触发器、操作等也定义在同一 rc 文件中。
/system/etc/init,包含系统核心服务的定义,如 SurfaceFlinger、MediaServer、Logcatd 等。 /vendor/etc/init, SOC 厂商针对 SOC 核心功能定义的一些服务。比如高通、MTK 某一款 SOC 的相关的服务。 /odm/etc/init,OEM/ODM 厂商如小米、华为、OPP 其产品所使用的外设以及差异化功能相关的服务。
查看 Android 7.0 虚拟机的 /system/etc/init 如下
上面的 ServiceManager 这个服务也从 init.rc 中拆分出来了。
4. 启动完成
至此,init 进程已经启动完成,一些重要的服务如 core 服务和 main 服务也都启动起来,并启动了zygote(/system/bin/app_process64)进程,zygote 初始化时会创建虚拟机,启动 SystemServer 等,它的启动过程也是非常复杂。
Zygote 的启动过程
0. 前言
上节文章的最后说到了 init 以 service 的方式启动了 Zygote 进程。这节文章主要讲 Zygote 进程的启动流程。
对于 Zygote 进程的描述如下:
在 Android 中,zygote 是整个系统创建新进程的核心。Zygote 进程在内部会先启动 Dalvik 虚拟机,继而加载一些必要的系统资源和系统类,最后进入一种监听状态。在后续的运作中,当其他系统模块(比如AMS)希望创建新进程时,只需向 Zygote 进程发出请求,Zygote 进程监听到该请求后,会相应地“分裂”出新的进程,于是这个新进程在初生之时,就先天具有了自己的 Dalvik 虚拟机以及系统资源。
1. 启动流程
/init.zygote64_32.rc 文件中启动 Zygote 的内容如下:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
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
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
在 dir/system/core/rootdir/ 目录下可以看到 init.zygote32.rc、init.zygote32_64.rc、init.zygote64.rc、init.zygote64_32.rc 等文件,这是因为 Android5.0 开始支持 64 位的编译,所以 Zygote 进程本身也有 32 位和 64 位版本。
从上面定义看到Zygote进程的可执行文件是 frameworks/base/cmds/app_process/app_main.cpp。
接下来分析 main 函数的流程。
1.1. 创建 AppRuntime 对象 AppRuntime 是在 app_process 中定义的类,继承了系统的 AndroidRuntime 类,AndroidRuntime 类的主要作用是创建和初始化虚拟机。
1.2. 解析启动参数
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;
}
}
从 init.rc 文件中传入的参数是 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote,解析后:
zygote = true;
niceName = zygoe;
startSystemServer = true;
1.3. 执行 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.");
return 10;
}
Zygote 经过解析参数后为 true, 所以会执行 runtime.start("com.android.internal.os.ZygoteInit", args, zygote); AndroidRuntime 的 start 方法实现在 dir/frameworks/base/core/jni/AndroidRuntime.cpp 中,
/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*
* Passes the main function two arguments, the class name and the specified
* options string.
*/
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
// 启动虚拟机,注册jni等
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
...
}
这个方法会启动 Android 运行环境,意味着它会启动 Android 虚拟机,并调用参数中 className 中的 main 方法。 从传入的 com.android.internal.os.ZygoteInit 类中找到 main 函数,即调用 ZygoteInit.java 类中的 main 方法。AndroidRuntime 及之前的方法都是 native 的方法,而此刻调用的 ZygoteInit.main 方法是 java 的方法,到这里我们就进入了 java 的世界。
调用示意图如下:
1.4. ZygoteInit 的 main 方法
ZygoteInit 定义在 dir/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 中。
public static void main(String argv[]) {
try {
...
registerZygoteSocket(socketName);
preload();
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
runSelectLoop(abiList);
...
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
主要工作:
- 注册Zygote的socket监听端口,应用接收启动应用程序的消息
- 调用preload()方法加载系统资源,包括预加载类,Framework资源等
- 调用startSystemServer()方法启动SystemServer进程
- 调用runSelectLoop()方法进入监听和接收消息循环
可见SystemServer是Zygote启动的第一个进程。
以上学习了 Android 系统的启动流程。
Great!
cool