1. 程式人生 > >Android 8.0 系統啟動流程之init.rc解析與service流程(七)

Android 8.0 系統啟動流程之init.rc解析與service流程(七)

1、概述

    上一篇文章中我們介紹了一下init.rc檔案中的語法規則,而本文將分析如何解析rc檔案,並對rc檔案中的某一service啟動過程進行分析。

2、解析.rc檔案

之前我們在文件中看到.rc檔案主要有根目錄下的 /init.rc ,以及{system,vendor,odm}/etc/init/這三個目錄下的 *.rc ,
然後就是如果有一個特殊目錄被設定的話,就替代這些目錄,明白這些,下面的程式碼就好理解了.

int main(int argc, char** argv) {
    ...
    const BuiltinFunctionMap function_map;
/* * 1.C++中::表示靜態方法呼叫,相當於java中static的方法 */ Action::set_function_map(&function_map); //將function_map存放到Action中作為成員屬性 Parser& parser = Parser::GetInstance();//單例模式,得到Parser物件 /* * 1.C++中std::make_unique相當於new,它會返回一個std::unique_ptr,即智慧指標,可以自動管理記憶體 * 2.unique_ptr持有對物件的獨有權,兩個unique_ptr不能指向一個物件,不能進行復制操作只能進行移動操作 * 3.移動操作的函式是 p1=std::move(p) ,這樣指標p指向的物件就移動到p1上了 * 4.接下來的這三句程式碼都是new一個Parser(解析器),然後將它們放到一個map裡存起來 * 5.ServiceParser、ActionParser、ImportParser分別對應service action import的解析 */
parser.AddSectionParser("service",std::make_unique<ServiceParser>()); parser.AddSectionParser("on", std::make_unique<ActionParser>()); parser.AddSectionParser("import", std::make_unique<ImportParser>()); std::string bootscript = GetProperty("ro.boot.init_rc", ""); if (bootscript.empty
()) {//如果ro.boot.init_rc沒有對應的值,則解析/init.rc以及/system/etc/init、/vendor/etc/init、/odm/etc/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 {//如果ro.boot.init_rc屬性有值就解析屬性值 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); } ... }

2.1 ParseConfig

定義在 platform/system/core/init/init_parser.cpp
首先是判斷傳入的是目錄還是檔案,若是檔案則呼叫ParseConfigFile;若是目錄則遞迴呼叫ParseConfigDir遍歷該目錄下的所有檔案,對檔案進行呼叫ParseConfigFile.

bool Parser::ParseConfig(const std::string& path) {
    if (is_dir(path.c_str())) {
        return ParseConfigDir(path);//遍歷下該目錄中的檔案
    }
    return ParseConfigFile(path);
}

而ParseConfigFile就是讀取檔案中的資料後,將資料傳遞給ParseData函式,最後遍section_parsers呼叫其EndFile函式,EndFile後面再分析,因為是多型實現,我們先看ParseData

bool Parser::ParseConfigFile(const std::string& path) {
    LOG(INFO) << "Parsing file " << path << "...";
    android::base::Timer t;
    std::string data;
    std::string err;
    if (!ReadFile(path, &data, &err)) {//將資料讀取到data
        LOG(ERROR) << err;
        return false;
    }

    data.push_back('\n'); // TODO: fix parse_config.
    ParseData(path, data);//解析資料
    for (const auto& [section_name, section_parser] : section_parsers_) {
        section_parser->EndFile();
    }

    LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
    return true;
}

2.2 ParseData

ParseData 定義在 platform/system/core/init/init_parser.cpp

ParseData通過呼叫next_token函式遍歷每一個字元,以空格或”“為分割將一行拆分成若干個單詞,呼叫T_TEXT將單詞放到args陣列中,當讀到回車符就呼叫T_NEWLINE,在section_parsers_這個map中找到對應的on service import的解析器,執行ParseSection,如果在map中找不到對應的key,就執行ParseLineSection,當讀到0的時候,表示一個Section讀取結束,呼叫T_EOF執行EndSection.

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()); //將data的內容複製到data_copy中
    data_copy.push_back('\0'); //追加一個結束符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)) { // 遍歷data_copy中每一個字元
        case T_EOF: //如果是檔案結尾,則呼叫EndSection
            if (section_parser) {
                section_parser->EndSection();
            }
            return;
        case T_NEWLINE://讀取了一行資料
            state.line++;
            if (args.empty()) {
                break;
            }
            /*
             * 1.section_parsers_是一個std:map
             * 2.C++中std:map的count函式是查詢key,相當於Java中Map的contains
             * 3.section_parsers_中只有三個key,on service import,之前AddSectionParser函式加入
             */
            if (section_parsers_.count(args[0])) { //判斷是否包含 on service import
                if (section_parser) {
                    section_parser->EndSection();
                }
                section_parser = section_parsers_[args[0]].get();//取出對應的parser
                std::string ret_err;
                if (!section_parser->ParseSection(args, &ret_err)) {//解析對應的Section
                    parse_error(&state, "%s\n", ret_err.c_str());
                    section_parser = nullptr;
                }
            } else if (section_parser) { //不包含 on service import則是command或option
                std::string ret_err;
                if (!section_parser->ParseLineSection(args, state.filename,
                                                      state.line, &ret_err)) {//解析command或option
                    parse_error(&state, "%s\n", ret_err.c_str());
                }
            }
            args.clear();
            break;
        case T_TEXT: //將讀取的一行資料放到args中,args以空格或""作為分割,將一行資料拆分成單詞放進陣列中
            args.emplace_back(state.text);
            break;
        }
    }
}

這裡其實涉及到on service import對應的三個解析器ActionParser,ServiceParser,ImportParser,它們是在之前加入到section_parsers_這個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>());

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

它們都是SectionParser的子類,SectionParser有四個純虛擬函式,分別是ParseSection、ParseLineSection、EndSection,EndFile.

class SectionParser {
public:
    virtual ~SectionParser() {
    }
    /*
     * 1.C++中純虛擬函式的定義格式是 virtual作為修飾符,然後賦值給0,相當於Java中的抽象方法
     * 2.如果不賦值給0,卻以virtual作為修飾符,這種是虛擬函式,虛擬函式可以有方法體,相當於Java中父類的方法,主要用於子類的過載
     * 3.只要包含純虛擬函式的類就是抽象類,不能new,只能通過子類實現,這個跟Java一樣
     */
    virtual bool ParseSection(const std::vector<std::string>& args,
                              std::string* err) = 0;
    virtual bool ParseLineSection(const std::vector<std::string>& args,
                                  const std::string& filename, int line,
                                  std::string* err) const = 0;
    virtual void EndSection() = 0;
    virtual void EndFile(const std::string& filename) = 0;
};

接下來我將分析這三個Perser的ParseSection、ParseLineSection、EndSection,EndFile具體實現

2.3 ActionParser

定義在platform/system/core/init/action.cpp

我們先看ParseSection,它先將args中下標1到結尾的資料複製到triggers陣列中,然後是構建Action物件,呼叫InitTriggers,解析這些trigger

bool ActionParser::ParseSection(const std::vector<std::string>& args,
                                std::string* err) {
    std::vector<std::string> triggers(args.begin() + 1, args.end()); //將args複製到triggers中,除去下標0
    if (triggers.size() < 1) {
        *err = "actions must have a trigger";
        return false;
    }

    auto action = std::make_unique<Action>(false);
    if (!action->InitTriggers(triggers, err)) { //呼叫InitTriggers解析trigger
        return false;
    }

    action_ = std::move(action);
    return true;
}

InitTriggers通過比較是否以”property:”開頭,區分trigger的型別,如果是property trigger,就呼叫ParsePropertyTrigger,如果是event trigger,就將args的引數賦值給event_trigger_,型別是string

bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err) {
    const static std::string prop_str("property:");
    for (std::size_t i = 0; i < args.size(); ++i) {

        ...

        if (!args[i].compare(0, prop_str.length(), prop_str)) {
            if (!ParsePropertyTrigger(args[i], err)) {
                return false;
            }
        } else {
           ...
            event_trigger_ = args[i];
        }
    }

    return true;
}

ParsePropertyTrigger函式先是將字元以”=”分割為name-value,然後將name-value存入property_triggers_這個map中

bool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err) {
    const static std::string prop_str("property:");
    std::string prop_name(trigger.substr(prop_str.length())); //擷取property:後的內容
    size_t equal_pos = prop_name.find('=');
    if (equal_pos == std::string::npos) {
        *err = "property trigger found without matching '='";
        return false;
    }

    std::string prop_value(prop_name.substr(equal_pos + 1)); //取出value
    prop_name.erase(equal_pos); //刪除下標為equal_pos的字元,也就是刪除"="

    if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) {
    //將name-value存放到map中,emplace相當於put操作
        *err = "multiple property triggers found for same property";
        return false;
    }
    return true;
}

從上面看出,ParseSection函式的作用就是構造一個Action物件,將trigger條件記錄到Action這個物件中,如果是event trigger就賦值給event_trigger_,如果是property trigger就存放到property_triggers_這個map中. 接下來我們分析ParseLineSection。ParseLineSection是直接呼叫Action物件的AddCommand函式

bool ActionParser::ParseLineSection(const std::vector<std::string>& args,
                                    const std::string& filename, int line,
                                    std::string* err) const {
    return action_ ? action_->AddCommand(args, filename, line, err) : false;
}

AddCommand看名字就大概知道是新增命令,它首先是做一些引數空值的檢查,然後是呼叫FindFunction查詢命令對應的執行函式,最後將這些資訊包裝成Command物件存放到commands_陣列中,這裡比較關鍵的就是FindFunction

bool Action::AddCommand(const std::vector<std::string>& args,
                        const std::string& filename, int line, std::string* err) {
    ... //一些引數檢查

    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_.emplace_back(f, args, filename, line);//commands_是個陣列,emplace_back就相當於add
}
FindFunction定義在platform/system/core/init/keyword_map.h

這個函式主要作用是通過命令查詢對應的執行函式,比如.rc檔案中定義chmod,那我們得找到chmod具體去執行哪個函式. 它首先是通過map()返回一個std:map,呼叫其find函式,find相當於Java中的get,但是返回的是entry,可以通過entry ->first和entry ->second獲取key-value。找到的value是一個結構體,裡面有三個值,第一個是引數最小數目,第二個是引數最大數目,第三個就是執行函式,之後作了引數的數目檢查,也就是說命令後的引數要在最小值和最大值之間.

const Function FindFunction(const std::string& keyword,
                                size_t num_args,
                                std::string* err) const {
        using android::base::StringPrintf;

        auto function_info_it = map().find(keyword); //找到keyword對應的entry
        if (function_info_it == map().end()) { // end是最後一個元素後的元素,表示找不到
            *err = StringPrintf("invalid keyword '%s'", keyword.c_str());
            return nullptr;
        }

        auto function_info = function_info_it->second;//獲取value

        auto min_args = std::get<0>(function_info);//獲取引數數量最小值
        auto max_args = std::get<1>(function_info);//獲取引數數量最大值
        if (min_args == max_args && num_args != min_args) {//將實際引數數量與最大值最小值比較
            *err = StringPrintf("%s requires %zu argument%s",
                                keyword.c_str(), min_args,
                                (min_args > 1 || min_args == 0) ? "s" : "");
            return nullptr;
        }

        if (num_args < min_args || num_args > max_args) {
            if (max_args == std::numeric_limits<decltype(max_args)>::max()) {
                *err = StringPrintf("%s requires at least %zu argument%s",
                                    keyword.c_str(), min_args,
                                    min_args > 1 ? "s" : "");
            } else {
                *err = StringPrintf("%s requires between %zu and %zu arguments",
                                    keyword.c_str(), min_args, max_args);
            }
            return nullptr;
        }

        return std::get<Function>(function_info);//返回命令對應的執行函式
    }

我們看看map()的實現,定義在platform/system/core/init/builtins.cpp

這個實現比較簡單,就是直接構造一個map,然後返回. 比如{“bootchart”, {1,1,do_bootchart}},表示命令名稱叫bootchart,對應的執行函式是do_bootchart,允許傳入的最小和最大引數數量是1

BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max(); //表示size_t的最大值
    // clang-format off
    static const Map builtin_functions = {
        {"bootchart",               {1,     1,    do_bootchart}},
        {"chmod",                   {2,     2,    do_chmod}},
        {"chown",                   {2,     3,    do_chown}},
        {"class_reset",             {1,     1,    do_class_reset}},
        {"class_restart",           {1,     1,    do_class_restart}},
        {"class_start",             {1,     1,    do_class_start}},
        {"class_stop",              {1,     1,    do_class_stop}},
        {"copy",                    {2,     2,    do_copy}},
        {"domainname",              {1,     1,    do_domainname}},
        {"enable",                  {1,     1,    do_enable}},
        {"exec",                    {1,     kMax, do_exec}},
        {"exec_start",              {1,     1,    do_exec_start}},
        {"export",                  {2,     2,    do_export}},
        {"hostname",                {1,     1,    do_hostname}},
        {"ifup",                    {1,     1,    do_ifup}},
        {"init_user0",              {0,     0,    do_init_user0}},
        {"insmod",                  {1,     kMax, do_insmod}},
        {"installkey",              {1,     1,    do_installkey}},
        {"load_persist_props",      {0,     0,    do_load_persist_props}},
        {"load_system_props",       {0,     0,    do_load_system_props}},
        {"loglevel",                {1,     1,    do_loglevel}},
        {"mkdir",                   {1,     4,    do_mkdir}},
        {"mount_all",               {1,     kMax, do_mount_all}},
        {"mount",                   {3,     kMax, do_mount}},
        {"umount",                  {1,     1,    do_umount}},
        {"restart",                 {1,     1,    do_restart}},
        {"restorecon",              {1,     kMax, do_restorecon}},
        {"restorecon_recursive",    {1,     kMax, do_restorecon_recursive}},
        {"rm",                      {1,     1,    do_rm}},
        {"rmdir",                   {1,     1,    do_rmdir}},
        {"setprop",                 {2,     2,    do_setprop}},
        {"setrlimit",               {3,     3,    do_setrlimit}},
        {"start",                   {1,     1,    do_start}},
        {"stop",                    {1,     1,    do_stop}},
        {"swapon_all",              {1,     1,    do_swapon_all}},
        {"symlink",                 {2,     2,    do_symlink}},
        {"sysclktz",                {1,     1,    do_sysclktz}},
        {"trigger",                 {1,     1,    do_trigger}},
        {"verity_load_state",       {0,     0,    do_verity_load_state}},
        {"verity_update_state",     {0,     0,    do_verity_update_state}},
        {"wait",                    {1,     2,    do_wait}},
        {"wait_for_prop",           {2,     2,    do_wait_for_prop}},
        {"write",                   {2,     2,    do_write}},
    };
    // clang-format on
    return builtin_functions;
}

接下來我們看看EndSection,直接是呼叫ActionManager::GetInstance().AddAction

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

AddAction首先是查詢是否有存在的同名Action,如果有就將他們的命令合併,沒有就將它存入陣列actions_中

void ActionManager::AddAction(std::unique_ptr<Action> action) {
    auto old_action_it =
        std::find_if(actions_.begin(), actions_.end(),
                     [&action] (std::unique_ptr<Action>& a) {
                         return action->TriggersEqual(*a);
                     });//find_if是集合中用於比較的模板,上面這種寫法是lambda表示式

    if (old_action_it != actions_.end()) {//在陣列actions中找到Action說明已經存在同名,就合併command
        (*old_action_it)->CombineAction(*action);
    } else { //找不到就加入陣列
        actions_.emplace_back(std::move(action));
    }
}

bool Action::TriggersEqual(const Action& other) const {
    return property_triggers_ == other.property_triggers_ &&
        event_trigger_ == other.event_trigger_;//比較之前記錄的event trigger和property trigger
}

void Action::CombineAction(const Action& action) {
    for (const auto& c : action.commands_) { //將新的Action中的command合併到老的Action
        commands_.emplace_back(c);
    }
}

EndFile是一個空實現,定義在platform/system/core/init/action.h

class ActionParser : public SectionParser {
public:
    ActionParser() : action_(nullptr) {
    }
    bool ParseSection(const std::vector<std::string>& args,
                      std::string* err) override;
    bool ParseLineSection(const std::vector<std::string>& args,
                          const std::string& filename, int line,
                          std::string* err) const override;
    void EndSection() override;
    void EndFile(const std::string&) override { //空實現
    }
private:
    std::unique_ptr<Action> action_;
};

講了這麼多,小結一下ActionParser做的事情. 它有三個重要的過載函式,ParseSection、ParseLineSection、EndSection.
ParseSection函式的作用是構造一個Action物件,將trigger條件記錄到Action這個物件中ParseLineSection作用是根據命令在一個map中找到對應的執行函式,然後將資訊記錄到之前構造的Action中EndSection作用是將前兩步構造的Action存入一個數組中,存入之前比較下陣列中是否已經存在同名的Action,如果有就合併command

2.4 ServiceParser

定義在platform/system/core/init/service.cpp

我們還是分析它的四個函式ParseSection、ParseLineSection、EndSection、EndFile
ParseSection首先是判斷單詞個數至少有三個,因為必須有一個服務名稱和執行檔案,然後是判斷名稱是否合法,主要是一些長度及內容的檢查,最後就是構造一個Service物件

bool ServiceParser::ParseSection(const std::vector<std::string>& args,
                                 std::string* err) {
    if (args.size() < 3) { // 傳入單詞個數至少三個
        *err = "services must have a name and a program";
        return false;
    }

    const std::string& name = args[1];
    if (!IsValidName(name)) {//檢查名稱是否合法
        *err = StringPrintf("invalid service name '%s'", name.c_str());
        return false;
    }

    std::vector<std::string> str_args(args.begin() + 2, args.end());
    service_ = std::make_unique<Service>(name, str_args);// 構造Service物件
    return true;
}

ParseLineSection直接執行Service的ParseLine函式

bool ServiceParser::ParseLineSection(const std::vector<std::string>& args,
                                     const std::string& filename, int line,
                                     std::string* err) const {
    return service_ ? service_->ParseLine(args, err) : false;
}

ParseLine的思路跟之前Action一樣,就是根據option名稱從map中找到對應的執行函式,然後執行這個函式.這些執行函式主要作用就是對傳入引數做一些處理,然後將資訊記錄到Service物件中

bool Service::ParseLine(const std::vector<std::string>& args, std::string* err) {
    if (args.empty()) {
        *err = "option needed, but not provided";
        return false;
    }

    static const OptionParserMap parser_map;
    auto parser = parser_map.FindFunction(args[0], args.size() - 1, err);//從map中找出執行函式

    if (!parser) {
        return false;
    }

    return (this->*parser)(args, err);//執行找到的這個函式
}

map()返回的map如下,定義在定義在platform/system/core/init/service.cpp中

Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    // clang-format off
    static const Map option_parsers = {
        {"capabilities",
                        {1,     kMax, &Service::ParseCapabilities}},
        {"class",       {1,     kMax, &Service::ParseClass}},
        {"console",     {0,     1,    &Service::ParseConsole}},
        {"critical",    {0,     0,    &Service::ParseCritical}},
        {"disabled",    {0,     0,    &Service::ParseDisabled}},
        {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
        {"ioprio",      {2,     2,    &Service::ParseIoprio}},
        {"priority",    {1,     1,    &Service::ParsePriority}},
        {"keycodes",    {1,     kMax, &Service::ParseKeycodes}},
        {"oneshot",     {0,     0,    &Service::ParseOneshot}},
        {"onrestart",   {1,     kMax, &Service::ParseOnrestart}},
        {"oom_score_adjust",
                        {1,     1,    &Service::ParseOomScoreAdjust}},
        {"namespace",   {1,     2,    &Service::ParseNamespace}},
        {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
        {"setenv",      {2,     2,    &Service::ParseSetenv}},
        {"socket",      {3,     6,    &Service::ParseSocket}},
        {"file",        {2,     2,    &Service::ParseFile}},
        {"user",        {1,     1,    &Service::ParseUser}},
        {"writepid",    {1,     kMax, &Service::ParseWritepid}},
    };
    // clang-format on
    return option_parsers;
}

接下來我們看看EndSection,直接呼叫ServiceManager的AddService函式

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

AddService的實現比較簡單,就是通過比較service的name,檢視存放Service的陣列services_中是否有同名的service,如果有就列印下錯誤日誌,直接返回,
如果不存在就加入陣列中

void ServiceManager::AddService(std::unique_ptr<Service> service) {
    Service* old_service = FindServiceByName(service->name()); //查詢services_中是否已存在同名service
    if (old_service) {
        LOG(ERROR) << "ignored duplicate definition of service '" << service->name() << "'";
        return;
    }
    services_.emplace_back(std::move(service));//加入陣列
}

Service* ServiceManager::FindServiceByName(const std::string& name) const {
    auto svc = std::find_if(services_.begin(), services_.end(),
                            [&name] (const std::unique_ptr<Service>& s) {
                                return name == s->name();
                            });//跟之前action一樣,遍歷陣列進行比較,查詢同名service
    if (svc != services_.end()) {
        return svc->get(); //找到就返回service
    }
    return nullptr;
}

EndFile依然是一個空實現,定義在platform/system/core/init/service.h

class ServiceParser : public SectionParser {
public:
    ServiceParser() : service_(nullptr) {
    }
    bool ParseSection(const std::vector<std::string>& args,
                      std::string* err) override;
    bool ParseLineSection(const std::vector<std::string>& args,
                          const std::string& filename, int line,
                          std::string* err) const override;
    void EndSection() override;
    void EndFile(const std::string&) override { //空實現
    }
private:
    bool IsValidName(const std::string& name) const;

    std::unique_ptr<Service> service_;
};

從上面可以看出,ServiceParser的處理跟ActionParser差不多,區別在於Action將執行函式存起來等待Trigger觸發時執行,Service找到執行函式後是馬上執行

2.4 ImportParser

定義在platform/system/core/init/import_parser.cpp

最後我們看看ImportParser,ImportParser的ParseLineSection、EndSection都是空實現,只實現了ParseSection和EndFile,因為它的語法比較單一,只有一行. 我們來看看它的ParseSection函式
首先檢查單詞只能是兩個,因為只能是import xxx 這種語法,然後呼叫expand_props處理下引數,最後將結果放入陣列imports_存起來

bool ImportParser::ParseSection(const std::vector<std::string>& args,
                                std::string* err) {
    if (args.size() != 2) { //檢查引數只能是兩個
        *err = "single argument needed for import\n";
        return false;
    }

    std::string conf_file;
    bool ret = expand_props(args[1], &conf_file); //處理第二個引數
    if (!ret) {
        *err = "error while expanding import";
        return false;
    }

    LOG(INFO) << "Added '" << conf_file << "' to import list";
    imports_.emplace_back(std::move(conf_file)); //存入陣列
    return true;
}

expand_props 定義在platform/system/core/init/util.cpp ,主要作用就是找到x.yx.y這種語法,將x.y取出來作為name,去屬性系統中找對應的value,然後替換

bool expand_props(const std::string& src, std::string* dst) {
    const char* src_ptr = src.c_str();

    if (!dst) {