第一次研究Zygote启动时还是4.0,目前已经Android版本已经发展到了10,变化还是蛮大的,一起来看看吧!

Android设备启动要经过3个阶段,BootLoaderLinux 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了!!!至于怎么解析的,我们后面再讲!