Android 8.0系統啓動流程_init(一)

本系列主要介紹Android8.0系統啓動過程當中涉及到的init、ZygoteSystemServerLauncherjava

  1. init啓動前準備
  2. init函數分析
  3. init函數解析
  4. init啓動Zygote

1、init啓動前準備

init進程是Android系統的第一個進程,其進程號爲1,該進程啓動後,主要處理一些重要的初始化工做,好比建立Zygote和各類屬性服務。在電源按鍵,按下後,經歷以下幾個步驟後,便開始引入init進程:linux

1. 啓動電源及系統:電源按下後,引導芯片開始將固化在ROM中的BootLoader加載至RAM中,並執行該程序; 2. 引導程序BootLoader:引導程序BootLoader是在Android操做系統開始運行前,執行的一個小程序,其主要做用是把系統OS拉起來並運行; 3. Linux內核啓動:內核啓動時,設置緩存、被保護存儲器、計劃列表和加載驅動等,完成設置後,開始加載init.rc文件; 4. init進程啓動:開始初始化和啓動屬性服務,建立Zygote進程。android

2、 init函數分析

在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

3、 init函數解析

\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
複製代碼

四 、init啓動Zygote

\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;
}


複製代碼

其主要流程以下:

  • 是否正在運行,如正在運行,直接返回;
  • 子進程是否啓動,如未啓動,調用fork並返回pid值;
  • 若是以上正常,則調用ExpandArgsAndExecve啓動該進程,完成Zygote的啓動。

啓動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.");
    }
...
 }

複製代碼
相關文章
相關標籤/搜索