天天看點

android8.1系統啟動過程(四) 解析init.rc

事先聲明本文為作者本人記錄學習使用

其中部分文字或者技術觀點摘自https://blog.csdn.net/marshal_zsx/article/details/80600622  這裡推薦此作者文章

main(int argc, char** argv)  AOSP/system/core/init/init.cpp

 這三句代碼都是new一個Parser(解析器),然後将它們放到一個map裡存起來  ServiceParser、ActionParser、ImportParser分别對應service action import的解析

parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sm));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&am));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
...
parser.ParseConfig("/init.rc");
           

ParseConfig()  AOSP/system/core/init/init_parser.cpp

判斷是檔案還是Dir或者是File  檔案調用ParseConfigFile

ParseConfigFile()  AOSP/system/core/init/init_parser.cpp  

取出資料調用  ParseData(path, data);

ParseData(path, data)  AOSP/platform/system/core/init/init_parser.cpp

取出對應的parser  解析對應的Section

section_parser = section_parsers_[args[0]].get();
std::string ret_err;
if (!section_parser->ParseSection(std::move(args), filename, state.line, &ret_err)) {
  LOG(ERROR) << filename << ": " << state.line << ": " << ret_err;
  section_parser = nullptr;
}
           

三個parser  這裡主要介紹serviceparser

Action  AOSP/system/core/init/action.cpp

Service  AOSP/system/core/init/service.cpp

ImportParser  AOSP/system/core/init/import_parser.cpp

經過以上的解析,系統從各種.rc檔案中讀取了需要執行的Action和Service,但是還是需要一些額外的配置,也需要加入觸發條件準備去觸發

main(int argc, char** argv)  AOSP/system/core/rootdir/init.cpp

    QueueEventTrigger用于觸發Action,這裡觸發 early-init事件

    QueueBuiltinAction用于添加Action,第一個參數是Action要執行的Command,第二個是Trigger

...
am.QueueEventTrigger("early-init");

// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
am.QueueBuiltinAction(set_kptr_restrict_action, "set_kptr_restrict");
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
am.QueueBuiltinAction(console_init_action, "console_init");
...
           

QueueEventTrigger()  AOSP/system/core/init/action.cpp

    它并沒有去觸發trigger,而是構造了一個EventTrigger對象,放到隊列中存起來

QueueBuiltinAction()  AOSP/system/core/init/action.cpp

QueueBuiltinAction(BuiltinFunction func, const std::string& name)
           

    這個函數有兩個參數,第一個參數是一個函數指針,第二參數是字元串. 首先是建立一個Action對象,将第二參數作為Action觸發條件,将第一個參數作為Action觸發後的執行指令,并且又把第二個參數作為指令的參數,最後是将Action加入觸發隊列并加入Action清單

main(int argc, char** argv)  AOSP/system/core/init/init.cpp

    觸發

while (true) {
    // By default, sleep until something happens.
    int epoll_timeout_ms = -1;

    if (do_shutdown && !shutting_down) {
        do_shutdown = false;
        if (HandlePowerctlMessage(shutdown_command)) {
            shutting_down = true;
        }
    }

    if (!(waiting_for_prop || sm.IsWaitingForExec())) {
        am.ExecuteOneCommand();
    }
    if (!(waiting_for_prop || sm.IsWaitingForExec())) {
        if (!shutting_down) restart_processes();
           

ExecuteOneCommand()  AOSP/system/core/init/action.cpp

    執行一個command,在函數一開始就從trigger_queue_隊列中取出一個trigger,然後周遊所有action,找出滿足trigger條件的action加入待執行清單current_executing_actions_中,接着從這個清單中取出一個action,執行它的第一個指令,并将指令所在下标自加1. 由于ExecuteOneCommand外部是一個無限循環,是以按照上面的邏輯一遍遍執行,将按照trigger表的順序,依次執行滿足trigger條件的action,然後依次執行action中的指令.

restart_processes()  AOSP/system/core/init/init.cpp

    主要是調用了    ForEachServiceWithFlags  RestartIfNeeded

static void restart_processes()
{
    process_needs_restart_at = 0;
    ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) {
        s->RestartIfNeeded(&process_needs_restart_at);
    });
}
           

ForEachServiceWithFlags()  AOSP/system/core/init/service.cpp

    周遊所有service,找出flags是SVC_RESTARTING的,執行func,也就是傳入的RestartIfNeeded

void ServiceManager::ForEachServiceWithFlags(unsigned matchflags,
                                             void (*func)(Service* svc)) const {
    for (const auto& s : services_) {
        if (s->flags() & matchflags) {
            func(s.get());
        }
    }
}
           

RestartIfNeeded()  AOSP/system/core/init/service.cpp

     這個函數将主要工作交給了Start,也就是具體的啟動service,但是交給它之前做了一些判斷,也就是5秒内隻能啟動一個服務,如果有多個服務,那麼後續的服務将進入等待

void Service::RestartIfNeeded(time_t* process_needs_restart_at) {
    boot_clock::time_point now = boot_clock::now();
    boot_clock::time_point next_start = time_started_ + 5s;
    if (now > next_start) {
        flags_ &= (~SVC_RESTARTING);
        Start();
        return;
    }

    time_t next_start_time_t = time(nullptr) +
        time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count());
    if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) {
        *process_needs_restart_at = next_start_time_t;
    }
}
           

Start()  AOSP/system/core/init/service.cpp

    Start是具體去啟動服務了,它主要是調用clone或fork建立子程序,然後調用execve執行配置的二進制檔案,另外根據之前在.rc檔案中的配置,去執行這些配置

bool Service::Start() {

    ... //清空标記,根據service的配置初始化console、SELinux政策等

    LOG(INFO) << "starting service '" << name_ << "'...";

    pid_t pid = -1;
    if (namespace_flags_) {//這個标記當service定義了namespace時會指派為CLONE_NEWPID|CLONE_NEWNS
        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr); //以clone方式在新的namespace建立子程序
    } else {
        pid = fork();//以fork方式建立子程序
    }

    if (pid == 0) {//表示建立子程序成功

        ... //執行service配置的其他參數,比如setenv、writepid等

        std::vector<char*> strs;
        ExpandArgs(args_, &strs);//将args_解析一下,比如有${x.y},然後指派表strs
        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) { //執行系統調用execve,也就是執行配置的二進制檔案,把參數傳進去
            PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
        }

        _exit(127);
    }

    if (pid < 0) { //子程序建立失敗
        PLOG(ERROR) << "failed to fork for '" << name_ << "'";
        pid_ = 0;
        return false;
    }

    ... //執行service其他參數如oom_score_adjust_,改變service運作狀态等
}