Android 啟動過程簡析(一)之 init 程式

ikroal發表於2017-10-28

問題

在進入到 Android 啟動過程之前先讓我們思考以下幾個問題

  1. Android 系統的啟動過程是怎樣的?
  2. init 、zygote 程式是什麼?在系統啟動的過程中各自發揮了什麼作用?
  3. AMS、PMS 等這些服務是如何被啟動的?
  4. Launcher 是如何被啟動的?

此篇文章將針對 init 部分給出分析

啟動流程簡述

在瞭解 init 部分之前,首先簡單介紹下系統的啟動流程以便抓住主線,當我們通過電源鍵開啟系統的時候,系統首先會載入 bootloader 程式到 RAM 中,然後通過 bootloader 將核心程式載入到 RAM 中,之後核心程式會建立init 程式,在 init 程式中會建立 zygote 程式,而 zygote 程式則會建立 DVM 並且啟動 SystemServer 程式,通過SystemServer 系統會啟動一系列的服務,包括常見的 AMS、PMS 等,最後再通過 AMS 進入到我們熟知的 Launcher 程式。

所以整個流程的關鍵點在於 init 程式如何建立 zygote、zygote 程式如何建立 SystemServer、SystemServer 程式如何啟動 AMS、AMS 如何啟動 Launcher。

init 啟動流程分析

由於 bootloader 和核心不是關心的重點,所以這裡只是簡單介紹它們的作用。

載入執行 BootLoader

在電源上電之後,CPU 中的操作控制器將發出控制訊號,將程式計數器(PC)的內容送至地址暫存器(AR),之後啟動對主存的讀操作,最終將 BootLoader 載入到 RAM 當中。然後 BootLoader 開始執行,主要負責硬體的初始化,將核心程式載入到記憶體。

init 程式的啟動

核心啟動之後將會初始化軟硬體環境,載入驅動程式,掛載根檔案系統,然後建立 init 程式,init 作為系統中的第一個使用者程式,其程式號為 1,在建立 init 程式之時,系統會執行位於 system/core/init 下的 init.cpp 程式

int main(int argc, char** argv) {
   ...
    //建立使用者空間目錄並掛載
    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);
    }

   ...

    signal_handler_init();

    property_load_boot_defaults();
    export_oem_lock_status();
    //啟動屬性服務
    start_property_service();

   ...

    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>());
    //解析 init.rc 檔案
    parser.ParseConfig("/init.rc");
   ...
    return 0;
}複製程式碼

可以看到 init 程式主要做了三件事情:建立使用者空間資料夾並掛載、啟動屬性服務、解析位於 system\core\rootdir 資料夾下的 init.rc 檔案

這裡我們主要關注解析 in it.rc 檔案的過程,因為 zygote 程式就是在這個過程中建立的。

Android Init Language

由於 init.rc 是一個用 Android 初始化語言(AIL)編寫的檔案,為了更好的理解 rc 檔案的解析過程需要了解一部分 AIL 語法。

AIL 主要有五種型別語句 Actions、Commands、Services、Options、Imports,在 AIL 中每個部分表示為一個 Section,比如:

on boot
    ifup lo
    hostname localhost
    domainname localdomain複製程式碼

五種語句中只有 Actions、Services、Import 可以用於確定一個 Section。其中 Actions 由一系列 command 組成,Actions 擁有一個 trigger 用於確定何時執行這些命令。

on <trigger>
    <command>
    <command>
    <command>

on early-init //觸發器 early-init
    write /proc/1/oom_score_adj -1000 //command
    write /proc/sys/kernel/sysrq 0複製程式碼

Services 由一些 option 組成,其在初始化的時候啟動,並可以在退出後重啟(可選)。

service <name> <pathname> [ <argument> ]*  //服務名、執行路徑、引數
        <option>  
        <option> 

service ueventd /sbin/ueventd 
    class core
    critical
    seclabel u:r:ueventd:s0複製程式碼

Services 定義了自身的服務名、執行路徑以及執行時傳入的引數,option 用於指定何時和怎樣啟動 service,關於何時啟動這裡進行一下說明,Actions 中有一條命令是 class_start <服務類別名> 用於啟動所有未執行的相同類別的 service,而 option 可以通過 class <類別名> 對 service 的類別名進行指定。所以 service 的啟動一般是通過 action 觸發之後執行 class_start 命令進行啟動的。

AIL 的介紹就到這了,如果想要詳細瞭解請閱讀 system/core/init 下的 readme.txt 檔案

init.rc 解析

現在接著分析 init.rc 檔案,在檔案的首部可以看到

import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc複製程式碼

在這裡可以看到需要啟動的 zygote,但是與其它引入的 rc 檔案相比 zygote 部分並沒有使用確定的值,而是使用 ${ro.zygote} 變數去替代,這是因為從 Android 在 5.0 以後開始支援 64 位程式,所以需要根據系統中 ro.zygote 屬性的值動態引入。ro.zygote 的值可以通過 adb shell getprop 進行查詢,我的手機查詢結果是:

這說明手機會啟動兩個 zygote 程式,對應的執行程式分別是 app_process64 (主模式)、app_process32,通過 adb shell ps | grep zygote 可以看到確實存在兩個 zygote 程式

接著檢視與 init.rc 同一目錄下的 init.zygote64_32.rc 檔案

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    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 /sys/fs/cgroup/stune/foreground/tasks

service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks複製程式碼

前文說過 service 的啟動和類別名相關,這裡兩個 zygote service 的類別名都是 main,所以要想知道 zygote 怎麼被啟動的我們可以在 init.rc 中搜尋 class_start main,可以發現

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複製程式碼

從這裡我們可以瞭解到當 nonencrypted 這個觸發器被觸發的時候 zygote 就會被啟動,所以啟動 zygote 的問題就轉變為這個觸發器什麼時候執行?class_start 對應的處理函式是什麼?要想知道答案,必須回到 init.cpp 的解析過程當中

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>());
parser.ParseConfig("/init.rc");複製程式碼

init.rc 交由一個 Parser 物件進行解析,而 Parser 的實現在 system/core/init/init_parser.cpp 檔案中,讓我們進入到 init_parser.cpp 中檢視 AddSectionParser 的實現

void Parser::AddSectionParser(const std::string& name,
                              std::unique_ptr<SectionParser> parser) {
    section_parsers_[name] = std::move(parser);
}

init_parser.h 中 section_parsers_ 的定義
std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;複製程式碼

可以看到每一個 parser 最終被儲存在 section_parsers_ 中,section_parsers_ 是什麼?檢視 init_parser.h 中的定義可以知道,sectionparsers 是一個 map 集合,所以 section_parsers_ 的作用是將 parser 與對應的 Section 進行繫結。

在新增完所有的 parser 之後就會呼叫 Parser 的 ParseConfig 方法

bool Parser::ParseConfig(const std::string& path) {
    if (is_dir(path.c_str())) {
        return ParseConfigDir(path);
    }
    return ParseConfigFile(path);
}複製程式碼

ParseConfig 中會對 path 進行判斷,如果是目錄則呼叫 ParseConfigDir 進行遞迴然後再通過 ParseConfigFile 進行解析。

bool Parser::ParseConfigDir(const std::string& path) {
    INFO("Parsing directory %s...\n", path.c_str());
    std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir);
    if (!config_dir) {
        ERROR("Could not import directory '%s'\n", path.c_str());
        return false;
    }
    dirent* current_file;
    while ((current_file = readdir(config_dir.get()))) {
        std::string current_path =
            android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
        // Ignore directories and only process regular files.
        if (current_file->d_type == DT_REG) {
            if (!ParseConfigFile(current_path)) { //呼叫 ParseConfigFile 進行解析
                ERROR("could not import file '%s'\n", current_path.c_str());
            }
        }
    }
    return true;
}複製程式碼

最終在 ParseConfigFile 中通過 ParseData 進行解析

bool Parser::ParseConfigFile(const std::string& path) {
    INFO("Parsing file %s...\n", path.c_str());
    Timer t;
    std::string data;
  //從 rc 檔案中讀取內容儲存在 data 中
    if (!read_file(path.c_str(), &data)) {
        return false;
    }

    data.push_back('\n'); // TODO: fix parse_config.
    ParseData(path, data); //呼叫 ParseData 進行解析
    ...
    return true;
}複製程式碼

ParseData 解析過程如下

void Parser::ParseData(const std::string& filename, const std::string& data) {
    //TODO: Use a parser with const input and remove this copy
    std::vector<char> data_copy(data.begin(), data.end()); //將 rc 中的內容儲存在 vector 中便於逐個字元進行解析
    data_copy.push_back('\0');

    parse_state state;
    state.filename = filename.c_str();
    state.line = 0;
    state.ptr = &data_copy[0];
    state.nexttoken = 0;

    SectionParser* section_parser = nullptr;
    std::vector<std::string> args; //存放的是每行的內容

    for (;;) {
        switch (next_token(&state)) {
        case T_EOF:
            if (section_parser) {
                section_parser->EndSection();
            }
            return;
        case T_NEWLINE:
            state.line++;
            //如果 args 為空則不進行解析(rc 檔案中間存在空行,所以需要判斷)
            if (args.empty()) {
                break;
            }
            //判斷是不是一個 section 的起始位置(通過能不能獲得解析器,可以判斷 args[0] 是不是 service、on、import 其中一個)
            if (section_parsers_.count(args[0])) {
                if (section_parser) {
                  //如果上次存在解析則結束解析
                    section_parser->EndSection();
                }
              //取出對應的解析器
                section_parser = section_parsers_[args[0]].get();
                std::string ret_err;
              //進行 Section 解析
                if (!section_parser->ParseSection(args, &ret_err)) {
                    parse_error(&state, "%s\n", ret_err.c_str());
                    section_parser = nullptr;
                }
            } else if (section_parser) { //不是的話說明 args 中是一個 section 的子塊,則進行 Line 解析
                std::string ret_err;
                if (!section_parser->ParseLineSection(args, state.filename,
                                                      state.line, &ret_err)) {
                    parse_error(&state, "%s\n", ret_err.c_str());
                }
            }
            //解析完成後清空
            args.clear();
            break;
        case T_TEXT:
            args.emplace_back(state.text);
            break;
        }
    }
}複製程式碼

ParseData 中通過呼叫 system/core/init/parser.cpp 中的 next_token 函式對 rc 內容進行分析,如果是 T_TEXT 則會儲存在 args 中,如果是 T_NEWLINE 則會交由對應的解析器進行解析。init.rc 的大致解析過程如此,但是到這裡我們依舊沒能找到所需要的答案,所以需要繼續檢視 ActionParser 和 ServiceParser 的解析過程。

ActionParser 解析過程

ActionParser 位於 system/core/init/ 的 action.cpp 中,從前面的解析過程來看,最後的解析總是呼叫了對應 parser 的 ParseSection、ParseLineSection 以及 EndSection,所以我們主要看下這兩個部分

ParseSection 的主要工作是建立 Action 物件,為物件新增觸發器,並將 action_ 移動至當前 Action 物件

bool ActionParser::ParseSection(const std::vector<std::string>& args,
                                std::string* err) {
    std::vector<std::string> triggers(args.begin() + 1, args.end());
    ...

    auto action = std::make_unique<Action>(false);
  //為 action 增加觸發器
    if (!action->InitTriggers(triggers, err)) {
        return false;
    }

  //將 aciton_ 指標移動到當前的 action
    action_ = std::move(action);
    return true;
}

//action_ 在 action.h 中的定義
private:
    std::unique_ptr<Action> action_;複製程式碼

ParseLineSection 的主要工作為查詢對應 command 的處理函式,將建立的 Command 物件新增到到commands_,由於 commands_ 是 Action 的一個域,所以實際上 ParseLineSection 在填充當前 Action 物件的域。

bool ActionParser::ParseLineSection(const std::vector<std::string>& args,
                                    const std::string& filename, int line,
                                    std::string* err) const {
  //將解析的 command 增加到當前 action 的 commands_ 中
    return action_ ? action_->AddCommand(args, filename, line, err) : false;
}

bool Action::AddCommand(const std::vector<std::string>& args,
                        const std::string& filename, int line, std::string* err) {
    ...
  //查詢對應的 command 的處理函式
    auto function = function_map_->FindFunction(args[0], args.size() - 1, err);
    if (!function) {
        return false;
    }

    AddCommand(function, args, filename, line);
    return true;
}

void Action::AddCommand(BuiltinFunction f,
                        const std::vector<std::string>& args,
                        const std::string& filename, int line) {
  //commands_ 增加 command 和對應的處理函式
    commands_.emplace_back(f, args, filename, line);
}

//commands_ 在 action.h 中的定義
std::vector<Command> commands_;

//Command 在 action.h 中的定義
class Command {
public:
    Command(BuiltinFunction f, const std::vector<std::string>& args,
            const std::string& filename, int line);

    int InvokeFunc() const;
    std::string BuildCommandString() const;
    std::string BuildSourceString() const;

private:
    BuiltinFunction func_;
    std::vector<std::string> args_;
    std::string filename_;
    int line_;
};複製程式碼

EndSection 的主要工作是將解析完成的 action (域填充完畢的 Action 物件)新增到 ActionManager 的 acitons_ 中

void ActionParser::EndSection() {
    if (action_ && action_->NumCommands() > 0) {
        ActionManager::GetInstance().AddAction(std::move(action_));
    }
}

void ActionManager::AddAction(std::unique_ptr<Action> action) {
    ...

    if (old_action_it != actions_.end()) {
        (*old_action_it)->CombineAction(*action);
    } else {
      //將解析之後的 action 物件增加到 actions_ 連結串列中,用於遍歷執行。
        actions_.emplace_back(std::move(action));
    }
}

//ActionManager 在 action.h 中的定義
class ActionManager {
public:
    static ActionManager& GetInstance();

    void AddAction(std::unique_ptr<Action> action);
    void QueueEventTrigger(const std::string& trigger);
    void QueuePropertyTrigger(const std::string& name, const std::string& value);
    void QueueAllPropertyTriggers();
    void QueueBuiltinAction(BuiltinFunction func, const std::string& name);
    void ExecuteOneCommand();
    bool HasMoreCommands() const;
    void DumpState() const;

private:
    ActionManager();

    ActionManager(ActionManager const&) = delete;
    void operator=(ActionManager const&) = delete;

    std::vector<std::unique_ptr<Action>> actions_; //actions_ 的定義
    std::queue<std::unique_ptr<Trigger>> trigger_queue_;
    std::queue<const Action*> current_executing_actions_;
    std::size_t current_command_;
};複製程式碼

通過以上分析我們能夠知道 class_start 的處理函式和 function_map_ 相關,檢視 function_map_ 在 action.h 中的定義可以看到

static const KeywordMap<BuiltinFunction>* function_map_;

static void set_function_map(const KeywordMap<BuiltinFunction>* function_map) {
    function_map_ = function_map;
}複製程式碼

所以要想知道處理函式是什麼只需要知道 set_function_map 在哪裡呼叫?讓我們再次回到 init.cpp 中,可以看到

const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);複製程式碼

接下來需要找到 BuiltinFunctionMap,BuiltinFunctionMap 的實現我們可以在 builtins.cpp 中找到,其具體的實現

BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    static const Map builtin_functions = {
        ...
        {"class_start",             {1,     1,    do_class_start}},
        {"class_stop",              {1,     1,    do_class_stop}},
        ...
    };
    return builtin_functions;
}複製程式碼

到這裡就可以確定 class_start 對應的處理函式是 do_class_start,do_class_start 也可在 builtins.cpp 中找到。

簡單總結下解析 Action 的過程,實際上是建立一個 Action 物件,然後為 Action 物件新增 Trigger 以及對應的 Command,其中在新增 Command 的過程中還為 Command 指定了處理函式,最後在將 Action 物件增加到 ActionManager vector 型別的 actions_ 連結串列當中去。

ServiceParser 解析過程

與前文一致,接著看那三個函式

ParseSection 的主要工作是建立 Service 物件,將 service_ 移動至當前 Service 物件

bool ServiceParser::ParseSection(const std::vector<std::string>& args,
                                 std::string* err) {
    ...
  //獲取服務名
    const std::string& name = args[1];
    ...
  //儲存服務名外的引數(如執行路徑等)
    std::vector<std::string> str_args(args.begin() + 2, args.end());
  //將 service_ 指標指向當前 Service 物件
    service_ = std::make_unique<Service>(name, "default", str_args);
    return true;
}

//service_ 在 service.h 中的定義
std::unique_ptr<Service> service_;複製程式碼

ParseLineSection 的主要工作是為 Service 中每個 option 指定處理函式

bool ServiceParser::ParseLineSection(const std::vector<std::string>& args,
                                     const std::string& filename, int line,
                                     std::string* err) const {
  //為 Service 中的每一個 Option 指定處理函式
    return service_ ? service_->HandleLine(args, err) : false;
}

bool Service::HandleLine(const std::vector<std::string>& args, std::string* err) {
    ...

    static const OptionHandlerMap handler_map;
  //尋找對應 option 的處理函式
    auto handler = handler_map.FindFunction(args[0], args.size() - 1, err);

    ...

    return (this->*handler)(args, err);
}複製程式碼

EndSection 的主要工作是將解析完成的 service (域填充完畢的 Service 物件)新增到 ServiceManager 的 services_ 中

void ServiceParser::EndSection() {
    if (service_) {
        ServiceManager::GetInstance().AddService(std::move(service_));
    }
}

void ServiceManager::AddService(std::unique_ptr<Service> service) {
    Service* old_service = FindServiceByName(service->name());
    if (old_service) {
        ERROR("ignored duplicate definition of service '%s'",
              service->name().c_str());
        return;
    }
  //將解析之後 service 物件增加到 services_ 連結串列中
    services_.emplace_back(std::move(service));
}

//ServiceManager 在 service.h 中的定義
class ServiceManager {
public:
    static ServiceManager& GetInstance();

    void AddService(std::unique_ptr<Service> service);
    Service* MakeExecOneshotService(const std::vector<std::string>& args);
    Service* FindServiceByName(const std::string& name) const;
    Service* FindServiceByPid(pid_t pid) const;
    Service* FindServiceByKeychord(int keychord_id) const;
    void ForEachService(std::function<void(Service*)> callback) const;
    void ForEachServiceInClass(const std::string& classname,
                               void (*func)(Service* svc)) const;
    void ForEachServiceWithFlags(unsigned matchflags,
                             void (*func)(Service* svc)) const;
    void ReapAnyOutstandingChildren();
    void RemoveService(const Service& svc);
    void DumpState() const;

private:
    ServiceManager();
    bool ReapOneProcess();
    static int exec_count_; // Every service needs a unique name.
    std::vector<std::unique_ptr<Service>> services_; //services_ 的定義
};複製程式碼

對應的可以看下 option 的處理函式,雖然 OptionHandlerMap 與啟動 zygote 無關,但是還是看下

Service::OptionHandlerMap::Map& Service::OptionHandlerMap::map() const {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    static const Map option_handlers = {
        {"class",       {1,     1,    &Service::HandleClass}},
        {"console",     {0,     0,    &Service::HandleConsole}},
        {"critical",    {0,     0,    &Service::HandleCritical}},
        {"disabled",    {0,     0,    &Service::HandleDisabled}},
        {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::HandleGroup}},
        {"ioprio",      {2,     2,    &Service::HandleIoprio}},
        {"keycodes",    {1,     kMax, &Service::HandleKeycodes}},
        {"oneshot",     {0,     0,    &Service::HandleOneshot}},
        {"onrestart",   {1,     kMax, &Service::HandleOnrestart}},
        {"seclabel",    {1,     1,    &Service::HandleSeclabel}},
        {"setenv",      {2,     2,    &Service::HandleSetenv}},
        {"socket",      {3,     6,    &Service::HandleSocket}},
        {"user",        {1,     1,    &Service::HandleUser}},
        {"writepid",    {1,     kMax, &Service::HandleWritepid}},
    };
    return option_handlers;
}複製程式碼

與解析 Action 類似,在整個過程中先建立 Service 物件,解析出 Service 的名字和對應的引數新增到物件當中,並且給每個 Option 指定了相應的處理函式

到這裡 rc 檔案的解析就結束了,通過 rc 檔案的解析使得每個 action 都有了對應的執行函式,所以接下來的問題是這些 action 是如何被觸發的(也即是 command 命令是如何被執行的)?

Actions 的觸發

讓我們繼續回到 init.cpp 中

ActionManager& am = ActionManager::GetInstance();
....

while (true) {
    if (!waiting_for_exec) {
        am.ExecuteOneCommand();
        restart_processes();
    }
...
}複製程式碼

可以看到 action 的 command 的執行是通過 ActionManager 的 ExecuteOneCommand 函式,而ActionManager 的 ExecuteOneCommand 最終呼叫了 Action 的 ExecuteOneCommand

void ActionManager::ExecuteOneCommand() {
    while (current_executing_actions_.empty() && !trigger_queue_.empty()) {
        //遍歷 actions_
        for (const auto& action : actions_) {
            if (trigger_queue_.front()->CheckTriggers(*action)) {
                //將 action 加入到 current_executing_actions_ 中
                current_executing_actions_.emplace(action.get());
            }
        }
        trigger_queue_.pop();
    }

    ...

    //每次只執行一個 action,下次 init 程式 while 迴圈時,跳過上面的 while 迴圈,接著執行
    auto action = current_executing_actions_.front();

    if (current_command_ == 0) {
        std::string trigger_name = action->BuildTriggersString();
        INFO("processing action (%s)\n", trigger_name.c_str());
    }

    //執行 action 的 command
    action->ExecuteOneCommand(current_command_);

    ++current_command_;
    ...
}

void Action::ExecuteOneCommand(std::size_t command) const {
  //執行 action 物件中儲存的 command
    ExecuteCommand(commands_[command]);
}

void Action::ExecuteCommand(const Command& command) const {
    Timer t;
  //呼叫 command 對應的處理函式
    int result = command.InvokeFunc();

    ...
}複製程式碼

通過上述分析可以知道,init 程式最終進入到無限迴圈中,然後按照 ActionManager 中 actions_ 儲存的 action 順序依次對每個 Action 進行處理,而在這個過程中 system/core/init/builtins.cpp 下用於啟動 zygote 的 do_class_start 函式將會被執行

static int do_class_start(const std::vector<std::string>& args) {
    ServiceManager::GetInstance().
        ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
    return 0;
}複製程式碼

do_class_start 函式中呼叫 Service 的 StartIfNotDisabled,StartIfNotDisabled 在 service.cpp 的實現如下

bool Service::StartIfNotDisabled() {
    if (!(flags_ & SVC_DISABLED)) {
        return Start();
    } else {
        flags_ |= SVC_DISABLED_START;
    }
    return true;
}複製程式碼

StartIfNotDisabled 最終呼叫了 Service 的 Start 函式,Start 函式建立了 zygote 的程式,並且執行了 init.zygote64_32.rc 中定義的執行路徑下的檔案

bool Service::Start() {
    ....
   //建立子程式
    pid_t pid = fork();
    if (pid == 0) {
        ...
       //執行對應 service 對應的執行檔案,args_[0].c_str() 就是執行路徑
        if (execve(args_[0].c_str(), (char**) &strs[0], (char**) ENV) < 0) {
            ERROR("cannot execve('%s'): %s\n", args_[0].c_str(), strerror(errno));
        }

        _exit(127);
    }

    ....
    return true;
}複製程式碼

在完成這一切之後將會進入 frameworks/base/cmds/app_process/app_main.cpp 中

int main(int argc, char* const argv[])
{
    ....

    if (zygote) {
      //啟動 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 最終在 app_main 的 main 函式中被啟動。

總結

到這裡我們就能夠回答對 init 部分相關的問題了

  1. init 的作用

    init 是系統中的第一個使用者程式,它的主要作用是建立使用者空間資料夾並掛載、啟動屬性服務、解析 init.rc 檔案並啟動 zygote 程式

  2. init 啟動 zygote 的過程

    init 程式通過解析 init.rc 檔案將 action 儲存在 ActionManager 的 actions_ 連結串列中,然後通過遍歷 actions_ 連結串列,執行 action 命令對應的處理函式,從而轉至 builtins.cpp 的 do_class_start 函式,之後通過 Service 的 StartIfNotDisabled 呼叫 Service 的 Start 函式,最終通過 Start 函式建立 zygote 程式,執行對應的 app_main.cpp 檔案啟動 zygote。

Thanks

  1. Android7.0 init程式原始碼分析
  2. Android Init Language(android初始化語言)
  3. Android系統啟動流程(一)解析init程式啟動過程

相關文章