Android系統(tǒng)啟動(dòng)分兩大階段:Linux階段,Android階段。
BootLoader啟動(dòng),引導(dǎo)進(jìn)入Linux內(nèi)核階段;Android啟動(dòng)階段,kernel_init函數(shù)完成設(shè)備驅(qū)動(dòng)程序的初始化,并調(diào)用init_post函數(shù)啟動(dòng)用戶空間的init進(jìn)程,Linux內(nèi)核啟動(dòng)完成之后跳轉(zhuǎn)到Android層init進(jìn)程啟動(dòng),從此開(kāi)啟了Android世界的大門(mén),整個(gè)開(kāi)機(jī)過(guò)程大致如下:

圖A-1
從圖A-1中可以看出,對(duì)于從事Android系統(tǒng)上層(非驅(qū)動(dòng))開(kāi)發(fā)人員,理解了init進(jìn)程啟動(dòng)之后階段的流程便知道系統(tǒng)進(jìn)程Systemserver, 諸如ActivityManagerService、PowerManagerService等核心服務(wù)如何啟動(dòng)的、怎么樣進(jìn)入我們常見(jiàn)的系統(tǒng)桌面(Launcher)應(yīng)用的。圖A-2 是init進(jìn)程啟動(dòng)后階段大致過(guò)程。

圖A-2
Init進(jìn)程啟動(dòng)在這里不做詳細(xì)的陳述,本文主要目的是打通整個(gè)開(kāi)機(jī)流程任督六脈,后續(xù)若有機(jī)會(huì)或時(shí)間,補(bǔ)寫(xiě)關(guān)于init進(jìn)程啟動(dòng)的詳細(xì)流程以及init.rc腳本的語(yǔ)法規(guī)則以及編寫(xiě)方法技巧,在此立帖為證,拜請(qǐng)監(jiān)督。
由圖A-2可知,內(nèi)核初始化階段會(huì)調(diào)用Kernel_init函數(shù),在這個(gè)函數(shù)中調(diào)用init_post函數(shù)啟動(dòng)祖先進(jìn)程,即init進(jìn)程。
01
Init啟動(dòng)【1】

圖A-3
文件路徑:/system/core/init/init.cpp。入口函數(shù)為main,代碼如下所示:
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}
// Clear the umask.
umask(0);
add_environment("PATH", _PATH_DEFPATH);
bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
// Get the basic filesystem setup we need put together in the initramdisk
// on / and then we'll let the rc file figure out the rest.
//1 創(chuàng)建文件并掛載
if (is_first_stage) {
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
define MAKE_STR(x) __STRING(x)
mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
mount("sysfs", "/sys", "sysfs", 0, NULL);
}
// We must have some place other than / to create the device nodes for
// kmsg and null, otherwise we won't be able to remount / read-only
// later on. Now that tmpfs is mounted on /dev, we can actually talk
// to the outside world.
open_devnull_stdio();
klog_init();
klog_set_level(KLOG_NOTICE_LEVEL);
NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");
if (!is_first_stage) {
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
//2 初始化屬性資源
property_init();
// If arguments are passed both on the command line and in DT,
// properties set in DT always have priority over the command-line ones.
process_kernel_dt();
process_kernel_cmdline();
// Propagate the kernel variables to internal variables
// used by init as well as the current required properties.
export_kernel_boot_props();
}
...
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
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>());
//3 解析init.rc腳本文件
parser.ParseConfig("/init.rc");
...
while (true) {
if (!waiting_for_exec) {
am.ExecuteOneCommand();
restart_processes();
}
int timeout = -1;
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
if (am.HasMoreCommands()) {
timeout = 0;
}
bootchart_sample(&timeout);
epoll_event ev;
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
if (nr == -1) {
ERROR("epoll_wait failed: %s\n", strerror(errno));
} else if (nr == 1) {
((void (*)()) ev.data.ptr)();
}
}
return 0;
}
從上述代碼片段可以分析可知,init進(jìn)程main函數(shù)做了許多事情,但是我們只需要關(guān)注幾點(diǎn)便可,1 is_first_stage為真時(shí)創(chuàng)建文件并掛載,2 調(diào)用property_init函數(shù)進(jìn)行初始化屬性相關(guān)資源,3 調(diào)用parser.ParseConfig("/init.rc")解析init.rc文件,至于怎么解析腳本文件在此不作闡述,如需深入理解可以跳轉(zhuǎn)至system/core/init/init_parse.cpp文件進(jìn)行自行閱讀,這里主要介紹zygote進(jìn)程是如何啟動(dòng)。
02
Zygote啟動(dòng)
講解Zygote啟動(dòng)之前先準(zhǔn)備一點(diǎn)預(yù)備知識(shí),Android7.0版本的系統(tǒng),Google對(duì)init.rc做了拆分,每個(gè)服務(wù)一個(gè)啟動(dòng)腳本,因本文是居于64Bit的Android7.0系統(tǒng)進(jìn)行分析的,故這里拿init.zygote64.rc文件進(jìn)行剖析,內(nèi)容如下:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
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服務(wù)的class name是main。從init啟動(dòng)部分流程圖看到main會(huì)去調(diào)用parser.ParseConfig("/init.rc")(system/core/init/init_parse.cpp),同學(xué)們可能會(huì)有一個(gè)疑問(wèn),為什么看不到init進(jìn)程去直接解析Zygote并啟動(dòng)?不急,且聽(tīng)我慢慢道來(lái)。從init.rc腳本開(kāi)頭處可以看到語(yǔ)句import /init.${ro.zygote}.rc,相當(dāng)于上面的init.zygote64.rc文件中的代碼內(nèi)容。init.rc代碼片段:
...
import /init.${ro.zygote}.rc
...
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
...
根據(jù)init.rc腳本語(yǔ)法語(yǔ)義規(guī)則,class_start是一個(gè)COMMAND,它對(duì)應(yīng)的函數(shù)是do_class_start,而我們從前面分析可知,main是指Zygote,所以此處是用來(lái)啟動(dòng)Zygote服務(wù)的。
system/core/init/builtins.cpp
static int do_class_start(const std::vector<std::string>& args) {
/* Starting a class does not start services
which are explicitly disabled. They must
be started individually.
*/
ServiceManager::GetInstance().
ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
return 0;
}
StartIfNotDisabled做了什么?
bool Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start(); //Service沒(méi)有運(yùn)行,則啟動(dòng)
} else {
flags_ |= SVC_DISABLED_START;
}
return true;
}
Start函數(shù)我們只需要關(guān)心兩點(diǎn),判斷啟動(dòng)service的執(zhí)行文件是否存在,如若不存在則不啟動(dòng)。否則創(chuàng)建子進(jìn)程調(diào)用execve執(zhí)行程序system/bin/app_process。

圖A-4
bool Service::Start() {
...
if (flags_ & SVC_RUNNING) { //如果service已經(jīng)運(yùn)行,則返回
ifdef MTK_INIT
ERROR("service '%s' still running, return directly\n", name_.c_str());
endif
return false;
}
...
//判斷啟動(dòng)service的執(zhí)行文件是否存在,如若不存在則返回
struct stat sb;
if (stat(args_[0].c_str(), &sb) == -1) {
ERROR("cannot find '%s' (%s), disabling '%s'\n",
args_[0].c_str(), strerror(errno), name_.c_str());
flags_ |= SVC_DISABLED;
return false;
}
...
pid_t pid = fork();
if (pid == 0) {
umask(077);
for (const auto& ei : envvars_) {
add_environment(ei.name.c_str(), ei.value.c_str());
}
for (const auto& si : sockets_) {
int socket_type = ((si.type == "stream" ? SOCK_STREAM :
(si.type == "dgram" ? SOCK_DGRAM :
SOCK_SEQPACKET)));
const char* socketcon =
!si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str();
int s = create_socket(si.name.c_str(), socket_type, si.perm,
si.uid, si.gid, socketcon);
if (s >= 0) {
PublishSocket(si.name, s);
}
}
...
if (execve(args_[0].c_str(), (char) &strs[0], (char) ENV) < 0) {
ERROR("cannot execve('%s'): %s\n", args_[0].c_str(), strerror(errno));
}
...
}
為了讓讀者們一目了然,根據(jù)代碼流程畫(huà)圖A-4流圖,希望能幫助理解代碼執(zhí)行流程。
我們進(jìn)入frameworks/base/cmds/app_process/app_main.cpp文件,代碼片段如下:
int main(int argc, char* const argv[])
{
...
//306行開(kāi)始
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分析了那么多,輾轉(zhuǎn)反側(cè),跋山涉水,終于看到啟動(dòng)Zygote的真正位置了。
找到frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件,看都做了那些事情?
public static void main(String argv[]) {
...
//判斷是否需要啟動(dòng)SystemServer
boolean startSystemServer = false;
String abiList = null;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = 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)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
...
//啟動(dòng)SystemServer進(jìn)程
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
}
03
SystemServer啟動(dòng)
依照?qǐng)DA-1,main方法里面我們只需要關(guān)心SystemServer啟動(dòng),其他的細(xì)枝末節(jié)暫不需要關(guān)注。SystemServer進(jìn)程在整個(gè)Android世界中起著非常重要的作用。與Zygote進(jìn)程一樣同等重要,同屬于Android的兩大進(jìn)程,系統(tǒng)很多核心進(jìn)程都是在這兩個(gè)進(jìn)程中開(kāi)啟的。
既然上文說(shuō)到調(diào)用startSystemServer方法啟動(dòng)SystemServer,那么我們來(lái)觀察SystemServer類內(nèi)都做了那些重要的事情?
/frameworks/base/services/java/com/android/server/SystemServer.java

圖A-5
從圖A-5中知道,SystemServer啟動(dòng)ActivityManagerService完成,在ActivityManagerService中會(huì)調(diào)用finishBooting方法完成引導(dǎo)過(guò)程,與此同時(shí)會(huì)發(fā)送開(kāi)機(jī)的廣播,當(dāng)系統(tǒng)指定的進(jìn)程接收到開(kāi)機(jī)廣播之后便會(huì)啟動(dòng)Home程序,完成Launcher桌面的加載和顯示。這樣Android的整個(gè)開(kāi)機(jī)過(guò)程就算完成了。很明顯,后面這一個(gè)過(guò)程遠(yuǎn)比我這里寫(xiě)的復(fù)雜得多,如果展開(kāi)分析的話會(huì)導(dǎo)致整篇文章篇幅過(guò)長(zhǎng),稍有不慎就成了裹腳布又長(zhǎng)又臭,所以這里就不作闡述了。【2】
總結(jié)
整個(gè)開(kāi)機(jī)過(guò)程大分為如下幾方面:
step1 BootLoader引導(dǎo)
step2 Kernel內(nèi)核加載
step3 Init祖先進(jìn)程啟動(dòng)
step4 Zygote進(jìn)程啟動(dòng)
step5 SystemServer進(jìn)程啟動(dòng)
step6 啟動(dòng)系統(tǒng)核心服務(wù)、服務(wù)庫(kù)等
step7 Home桌面加載和顯示
PS:后期如有時(shí)間,會(huì)詳細(xì)分析init進(jìn)程的啟動(dòng)過(guò)程,以及最后階段是怎么一步一步啟動(dòng)Home桌面程序的,即文中標(biāo)注【1】【2】處。