第一次研究Zygote启动时还是4.0,目前已经Android版本已经发展到了10,变化还是蛮大的,一起来看看吧!
Android设备启动要经过3个阶段,BootLoader、Linux Kernel和Android系统服务,Android系统实际上是运行于Linux内核之上的一系列"服务进程",并不算一个完成意义上的"操作系统";而这一系列进程是维持Android设备正常工作的关键,所以它们肯定有一个"根进程",这个"根进程"衍生出了这一系列进程。这个"根进程"就是init进程。init进程是Android系统启动的第一个进程。它通过解析init.rc脚本来构建出系统的初始形态。其他的"一系列"Android系统进程大部分也是通过"init.rc"来启动的。因为要兼容不同的开发商,所以init.rc脚本的语法很简单,并且采用的是纯文本编辑的,这样导致它可读性就会很高。
下面我们就来看看这个init进程是如何解析init.rc并根据其语法启动相应的进程的吧!我们要分析init进程,首先要知道init所对应的代码。这里怎么去找呢?我们知道,Android.mk和Android.bp定义了Android源码的编译规则,所以想要找到init所对应的源码还得从他们俩入手。使用命令“ find ./ -name Android.mk -exec grep -l init {} \;”就可以找到含有字符串init的所有Android.mk,至于具体是哪一个Android.mk文件,这就需要我们自己打开后自己筛选了!这里我们初步判断是“system/core/init/Android.mk”,这其中就有:
46 include $(CLEAR_VARS)
47 LOCAL_CPPFLAGS := $(init_cflags)
48 LOCAL_SRC_FILES := \
49 devices.cpp \
50 first_stage_init.cpp \
51 first_stage_main.cpp \
52 first_stage_mount.cpp \
53 mount_namespace.cpp \
54 reboot_utils.cpp \
55 selinux.cpp \
56 switch_root.cpp \
57 uevent_listener.cpp \
58 util.cpp \
59
60 LOCAL_MODULE := init_first_stage
61 LOCAL_MODULE_STEM := init
62
63 LOCAL_FORCE_STATIC_EXECUTABLE := true
64
65 LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)
66 LOCAL_UNSTRIPPED_PATH := $(TARGET_RAMDISK_OUT_UNSTRIPPED)
67
68# Install adb_debug.prop into debug ramdisk.
69 # This allows adb root on a user build, when debug ramdisk is used.
70 LOCAL_REQUIRED_MODULES := \
71 adb_debug.prop \
72
73 # Set up the same mount points on the ramdisk that system-as-root contains.
74 LOCAL_POST_INSTALL_CMD := mkdir -p \
75 $(TARGET_RAMDISK_OUT)/apex \
76 $(TARGET_RAMDISK_OUT)/debug_ramdisk \
77 $(TARGET_RAMDISK_OUT)/dev \
78 $(TARGET_RAMDISK_OUT)/mnt \
79 $(TARGET_RAMDISK_OUT)/proc \
80 $(TARGET_RAMDISK_OUT)/sys \
81
82 LOCAL_STATIC_LIBRARIES := \
83 libc++fs \
84 libfs_avb \
85 libfs_mgr \
86 libfec \
87 libfec_rs \
88 libsquashfs_utils \
89 liblogwrap \
90 libext4_utils \
91 libfscrypt \
92 libseccomp_policy \
93 libcrypto_utils \
94 libsparse \
95 libavb \
96 libkeyutils \
97 liblp \
98 libcutils \
99 libbase \
100 liblog \
101 libcrypto \
102 libdl \
103 libz \
104 libselinux \
105 libcap \
106 libgsi \
107 libcom.android.sysprop.apex \
108 liblzma \
109 libdexfile_support \
110 libunwindstack \
111 libbacktrace \
112
113 LOCAL_SANITIZE := signed-integer-overflow
114 # First stage init is weird: it may start without stdout/stderr, and no /proc.
115 LOCAL_NOSANITIZE := hwaddress
116 include $(BUILD_EXECUTABLE) #生成可执行文件
基本都是C++文件,那入口在哪里呢?CPP的入口也是main方法,其中我们猜测是first_stage_main.cpp,打开文件我们看到
17 #include "first_stage_init.h"
18
19 int main(int argc, char** argv) {
20 return android::init::FirstStageMain(argc, argv);
21 }
果不其然,是我们要找的main,我们就不要客气,直接找“android::init::FirstStageMain(argc, argv);”,这个方法在core/init/first_stage_init.cpp中实现。这个文件的带我我就不贴了,主要是在ramdisk文件系统里创建一个目录并挂载,但是我没有找到加载解析init.rc的地方。
看到这里,有点懵,怎么刚开始就结束了,好在根据我经验丰富,这里有好多First Stage 字样,是不是还有Second 或者还有Third呢?其实靠谱的做法我猜测和内核启动参数挂载启动文件系统有关(仅猜测,未验证),,但不管怎样,可以找找看!果不其然,还真有Second State。
在“system/core/init/Android.bp”文件中我们发现了
155 cc_binary {
156 name: "init_second_stage",
157 recovery_available: true,
158 stem: "init",
159 defaults: ["init_defaults"],
160 static_libs: ["libinit"],
161 required: [
162 "e2fsdroid",
163 "mke2fs",
164 "sload_f2fs",
165 "make_f2fs",
166 ],
167 srcs: ["main.cpp"],
168 symlinks: ["ueventd"],
169 target: {
170 recovery: {
171 cflags: ["-DRECOVERY"],
172 exclude_shared_libs: ["libbinder", "libutils"],
173 },
174 },
175 ldflags: ["-Wl,--rpath,/system/${LIB}/bootstrap"],
176 }
这里就去看看main.cpp
51 int main(int argc, char** argv) {
52 #if __has_feature(address_sanitizer)
53 __asan_set_error_report_callback(AsanReportCallback);
54 #endif
55
56 if (!strcmp(basename(argv[0]), "ueventd")) {
57 return ueventd_main(argc, argv);
58 }
59
60 if (argc > 1) {
61 if (!strcmp(argv[1], "subcontext")) {
62 android::base::InitLogging(argv, &android::base::KernelLogger);
63 const BuiltinFunctionMap function_map;
64
65 return SubcontextMain(argc, argv, &function_map);
66 }
67
68 if (!strcmp(argv[1], "selinux_setup")) {
69 return SetupSelinux(argv);
70 }
71
72 if (!strcmp(argv[1], "second_stage")) {
73 return SecondStageMain(argc, argv);
74 }
75 }
76
77 return FirstStageMain(argc, argv);
78 }
这里果然有对输入参数的判断,有兴趣的同学可以去研究内核挂载文件系统的参数传递吧,我这里先不看了!
我们看到最后面有 “return SecondStageMain(argc, argv);”,这个应该就是我们要找的二段!
具体实现在system/core/init/init.cpp
这里做了一大堆事情,基本和之前的Android版本没甚区别,大家可以去网上搜一些之前Android版本的看一下。在706行我发现了
“LoadBootScripts(am, sm);” 跟踪发现:
127 static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
128 Parser parser = CreateParser(action_manager, service_list);
129
130 std::string bootscript = GetProperty("ro.boot.init_rc", "");
131 if (bootscript.empty()) {
132 parser.ParseConfig("/init.rc");
133 if (!parser.ParseConfig("/system/etc/init")) {
134 late_import_paths.emplace_back("/system/etc/init");
135 }
136 if (!parser.ParseConfig("/product/etc/init")) {
137 late_import_paths.emplace_back("/product/etc/init");
138 }
139 if (!parser.ParseConfig("/product_services/etc/init")) {
140 late_import_paths.emplace_back("/product_services/etc/init");
141 }
142 if (!parser.ParseConfig("/odm/etc/init")) {
143 late_import_paths.emplace_back("/odm/etc/init");
144 }
145 if (!parser.ParseConfig("/vendor/etc/init")) {
146 late_import_paths.emplace_back("/vendor/etc/init");
147 }
148 } else {
149 parser.ParseConfig(bootscript);
150 }
151 }
看到了吧,这里就去解析init.rc了!!!至于怎么解析的,我们后面再讲!