本系列主要介紹Android8.0系統啓動過程當中涉及到的init、Zygote、SystemServer和Launcher。java
init進程是Android系統的第一個進程,其進程號爲1,該進程啓動後,主要處理一些重要的初始化工做,好比建立Zygote和各類屬性服務。在電源按鍵,按下後,經歷以下幾個步驟後,便開始引入init進程:linux
1. 啓動電源及系統:電源按下後,引導芯片開始將固化在ROM中的BootLoader加載至RAM中,並執行該程序; 2. 引導程序BootLoader:引導程序BootLoader是在Android操做系統開始運行前,執行的一個小程序,其主要做用是把系統OS拉起來並運行; 3. Linux內核啓動:內核啓動時,設置緩存、被保護存儲器、計劃列表和加載驅動等,完成設置後,開始加載init.rc文件; 4. init進程啓動:開始初始化和啓動屬性服務,建立Zygote進程。android
在Linux內核加載完成後,開始查找init.rc文件,並啓動init進程,其主要代碼以下:小程序
system/core/init/init.cpp緩存
int main(int argc, char** argv) {
...
if (is_first_stage) {
boot_clock::time_point start_time = boot_clock::now();
// 清理 umask.
umask(0);
// 建立和掛載所需的文件
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));
// Don't expose the raw commandline to unprivileged processes. chmod("/proc/cmdline", 0440); gid_t groups[] = { AID_READPROC }; setgroups(arraysize(groups), groups); mount("sysfs", "/sys", "sysfs", 0, NULL); mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL); mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)); mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)); mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)); // 初始化Kernel日誌 InitKernelLogging(argv); ... } ... //屬性服務初始化 property_init(); ... //建立epoll句柄 epoll_fd = epoll_create1(EPOLL_CLOEXEC); ... //設置子進程的處理函數 signal_handler_init(); //導入默認的環境變量 property_load_boot_defaults(); export_oem_lock_status(); //啓動屬性服務 start_property_service(); set_usb_controller(); ... if (bootscript.empty()) { //解析init.rc文件 parser.ParseConfig("/init.rc"); parser.set_is_system_etc_init_loaded( parser.ParseConfig("/system/etc/init")); parser.set_is_vendor_etc_init_loaded( parser.ParseConfig("/vendor/etc/init")); parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init")); } else { parser.ParseConfig(bootscript); parser.set_is_system_etc_init_loaded(true); parser.set_is_vendor_etc_init_loaded(true); parser.set_is_odm_etc_init_loaded(true); } ... return 0; } 複製代碼
該流程分析以下:bash
1. 掛載文件:經過設置umask值,屏蔽一些權限後,開始掛載和建立所需的文件; 2. 屬性服務:經過property_init()屬性服務初始化,調用start_property_service()啓動屬性服務; 3. 子進程的處理函數: signal_handler_init()主要做用是防止出現殭屍進程,子進程在暫停和終止後,會發出SIGCHLD的信號,signal_handler_init()接收到該信號後,會對該進程進行回收處理,防止佔用系統進程資源; 4. 解析init.rc配置:在8.0中對init.rc文件進行了拆分,可查看system\core\rootdir目錄,包括: init.zygote32.rc:Zygote對應的執行程序是app_process(純32位模式); init.zygote64.rc:Zygote對應的執行程序是app_process64(純64位模式); init.zygote32_64.rc:啓動兩個Zygote進程( zygote 和 zygote_secondary),對應的執行程序是app_process32(主模式)和app_process64; init.zygote64_32.rc:啓動兩個Zygote進程( zygote 和 zygote_secondary),對應的執行程序是app_process64(主模式)和app_process32。app
\system\core\rootdir\init.rcdom
init.rc配置文件,是由Android初始化語言(Android Init Language)編寫的腳本,主要包括5種語言類型:Action、Command、Service、Option和Import。 同時,須要注意init.rc僅僅是配置文件,相似於xml,沒有解析的順序而言(不是自上而下運行),是經過程序調用,獲取相應的配置信息,真正加載運行的程序是在上部分提到的init.cpp文件。socket
import:指令是用於相似於java語言,主要用於擴展配置,格式以下:ide
import <filename>一個init配置文件,擴展當前配置
複製代碼
filename通常是init.XXX.rc的形式,源碼中例如:
import /init.environ.rc
複製代碼
Action:一系列命令的開始,其格式以下:
on <trgger> [&& <trigger>]*
<command1>
<command2>
<command3>
...
複製代碼
每一個Action都至少有一個觸發器(trgger),該觸發器決定什麼時候執行該Action,即後面的command...指令,其要經過ActionParser解析,其實現代碼在\system\core\init\action.cpp,其格式以下:
# Indicate to fw loaders that the relevant mounts are up.
on firmware_mounts_complete
rm /dev/.booting
複製代碼
Service:以service開頭,由init進程啓動的,通常運行於init的子進程中,在啓動該service前須要判斷對應的可執行文件是否存在,並經過fork方式生成子進程。其主要經過ServiceParser解析,其實現代碼在\system\core\init\service.cpp,其格式以下:
service <name> <pathname> [ <argument> ]*
<option>
<option>
...
複製代碼
其中name:服務的名稱,pathname:當前服務對應程序的位置,option:當前服務設置的選項,argument:可選參數。例如:
service ueventd /sbin/ueventd
class core
critical
seclabel u:r:ueventd:s0
shutdown critical
複製代碼
\system\core\rootdir\init.rc \system\core\init\init.cpp \system\core\init\builtins.cpp \ frameworks\base\cmds\app_process\app_main.cpp
在init.rc中,關於Zygote的啓動在以下部分:
\system\core\rootdir\init.rc
on nonencrypted
class_start main
class_start late_start
複製代碼
其中 main指的就是Zygote的服務名稱,其中class_start函數是指builtins.cpp中的函數:
\system\core\init\builtins.cpp
static int do_class_start(const std::vector<std::string>& args) {
ServiceManager::GetInstance().
ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
return 0;
}
複製代碼
其中ForEachServiceInClass函數會遍歷Service鏈表,查找classname爲main的Zygote,並執行service.cpp中的StartIfNotDisabled函數,以下所示:
\system\core\init\service.cpp
bool Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start();
} else {
flags_ |= SVC_DISABLED_START;
}
return true;
}
複製代碼
若是該service沒有在其對應的rc文件中設置disable選項,則會執行Start()方法,啓動該Service,在init.zygote64.rc中沒有設置disable選項,所以能夠正常啓動該Service。
\system\core\init\builtins.cpp
bool Service::Start() {
..
//是否正在運行
if (flags_ & SVC_RUNNING) {
return false;
}
...
//啓動的路徑是否存在
struct stat sb;
if (stat(args_[0].c_str(), &sb) == -1) {
PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
flags_ |= SVC_DISABLED;
return false;
}
std::string scon;
if (!seclabel_.empty()) {
scon = seclabel_;
} else {
scon = ComputeContextFromExecutable(name_, args_[0]);
if (scon == "") {
return false;
}
}
//若是該進程未啓動,調用fork啓動該進程
pid_t pid = -1;
if (namespace_flags_) {
pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
} else {
pid = fork();
}
if (pid == 0) {
umask(077);
...
}
if (pid < 0) {
PLOG(ERROR) << "failed to fork for '" << name_ << "'";
pid_ = 0;
return false;
}
....
//啓動該進程
SetProcessAttributes();
if (!ExpandArgsAndExecve(args_)) {
PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
}
_exit(127);
NotifyStateChange("running");
return true;
}
複製代碼
其主要流程以下:
啓動Zygote進程真正執行的路徑爲frameworks\base\cmds\app_process\app_main.cpp下的main函數,以下所示:
\ frameworks\base\cmds\app_process\app_main.cpp
int main(int argc, char* const argv[])
{
...
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//啓動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.");
}
...
}
複製代碼