安卓11.0系统源码解析之系统启动流程分析(一)解析工具分析

933 阅读9分钟

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

系统启动流程分析之解析工具分析

在安卓11.0系统启动源码中,此前我们有分析过,在系统启动中,调用SecondStageMain函数来启动zygote以及系统服务,而在这个过程中,有一个很重要的环节就是,解析配置文件,而要解析配置文件,首先得要建立解析工具。

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    // 1. 创建对应的解析工具
    Parser parser = CreateParser(action_manager, service_list);
    // 2. 获取对应的解析文件
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    // 若ro.boot.init_rc指向对应的解析文件未定义,则直接解析指定的解析文件
    if (bootscript.empty()) {
        parser.ParseConfig("/system/etc/init/hw/init.rc");
        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        // late_import is available only in Q and earlier release. As we don't
        // have system_ext in those versions, skip late_import for system_ext.
        parser.ParseConfig("/system_ext/etc/init");
        if (!parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
        if (!parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
    } else {
         // 若ro.boot.init_rc属性已定义,则直接解析其指向的配置文件
        parser.ParseConfig(bootscript);
    }
}

从代码中看,系统源码中使用LoadBootScripts函数来解析配置文件,而在这边,会通过CreateParser函数,来创建三个不同类别的解析工具,接下来,我们就来分析下,这三个配置解析工具是如何解析对应的配置文件的。

Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser;
    parser.AddSectionParser("service", std::make_unique<ServiceParser>(
                                               &service_list, GetSubcontext(), std::nullopt));
    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
    parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
    return parser;
}

CreateParser函数,有两个参数,ActionManager对象和ServiceList对象,这两个对象的初始化在前文中,我们不做分析,主要是初始化工作。该函数返回一个Parser对象(解析器),这个我们稍后遇到后再行分析。

首先,通过Parser对象的AddSectionParser函数,往Parser对象中添加了三个对应的解析工具。

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

可以看到,在Parser对象中定义了名称为section_parsers_的map,然后将三个解析工具添加到该map中,可以看到,对应的key分别为”service”、”on”和“import”,而对应的,其value对应的对象,均继承于SectionParser类,而SectionParser的定义很简单。

system/core/init/parser.h
class SectionParser {
  public:
    virtual ~SectionParser() {}
    virtual Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
                                      int line) = 0;
    virtual Result<void> ParseLineSection(std::vector<std::string>&&, int) { return {}; };
    virtual Result<void> EndSection() { return {}; };
    virtual void EndFile(){};
};

接下来,我们一一分析一下三个解析工具

解析器的入口:Parser解析器

初始化

Parser::Parser() {}

开始解析

解析的过程,从上述的LoadBootScripts函数中,可致,通过调用Parser的ParseConfig函数来启动解析,那么此处,我们开始, parser.ParseConfig(bootscript); 此处,由于我们需要解析的是/system/core/rootdir/init.zygote32.rc文件,所以此处的bootscript为/system/core/rootdir/init.zygote32.rc字符串

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

判断当前传入路径是否是文件夹,若为文件夹,则调用ParseConfigDir来解析该文件夹下的每一个配置文件,而此处我们传入的是一个文件,因此ParseConfigFile函数

bool Parser::ParseConfigFile(const std::string& path) {
    LOG(INFO) << "Parsing file " << path << "...";
    android::base::Timer t;
    // 1. 从文件中读取对应的配置文件中的所有内容,保存为字符串形式
    auto config_contents = ReadFile(path);
    if (!config_contents.ok()) {
        LOG(INFO) << "Unable to read config file '" << path << "': " << config_contents.error();
        return false;
    }
    // 2. 调用ParseData函数,解析上述配置文件中的所有配置内容
    ParseData(path, &config_contents.value());
    LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
    return true;
}

从上述代码可知,此处有两个步骤

从文件中读取对应的配置文件中的所有内容,保存为字符串形式,这部分,在此处不再分析

其次,调用ParseData函数,来解析对应的配置文件内容

void Parser::ParseData(const std::string& filename, std::string* data) {
    // 1. 给解析数据的末尾添加结束符
    data->push_back('\n');
    data->push_back('\0');
    // 解析状态数据
    parse_state state;
    state.line = 0;
    state.ptr = data->data();
    state.nexttoken = 0;
    SectionParser* section_parser = nullptr;
    int section_start_line = -1;
    std::vector<std::string> args;
 
    // If we encounter a bad section start, there is no valid parser object to parse the subsequent
    // sections, so we must suppress errors until the next valid section is found.
    bool bad_section_found = false;
    // 2. 定义一个end_section函数
    // 函数的主要作用是,当配置文件数据解析完成后,做一些关闭操作
    auto end_section = [&] {
        bad_section_found = false;
        if (section_parser == nullptr) return;
 
        if (auto result = section_parser->EndSection(); !result.ok()) {
            parse_error_count_++;
            LOG(ERROR) << filename << ": " << section_start_line << ": " << result.error();
        }

        section_parser = nullptr;
        section_start_line = -1;
    };

    3. 无限循环,解析配置数据
    for (;;) {
        switch (next_token(&state)) {
             // 配置文件解析完成
            case T_EOF:
                end_section();
                for (const auto& [section_name, section_parser] : section_parsers_) {
                    section_parser->EndFile();
                }
                return;
             // 配置文件解析新的一行数据
            case T_NEWLINE: {
                // 确认解析第几行
                state.line++;
                if (args.empty()) break;
                // If we have a line matching a prefix we recognize, call its callback and unset any
                // current section parsers.  This is meant for /sys/ and /dev/ line entries for
                // uevent.
                // 从字符串中查找以args[0]开头的对应的子字符串
                auto line_callback = std::find_if(
                    line_callbacks_.begin(), line_callbacks_.end(),
                    [&args](const auto& c) { return android::base::StartsWith(args[0], c.first); });
                if (line_callback != line_callbacks_.end()) {
                    // end_section
                    end_section();
                    if (auto result = line_callback->second(std::move(args)); !result.ok()) {
                        parse_error_count_++;
                        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                    }
                } else if (section_parsers_.count(args[0])) {
                    end_section();
                    // 获取解析工具
                    section_parser = section_parsers_[args[0]].get();
                    section_start_line = state.line;
                    // 解析Section
                    if (auto result =
                                section_parser->ParseSection(std::move(args), filename, state.line);
                        !result.ok()) {
                        parse_error_count_++;
                        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                        section_parser = nullptr;
                        bad_section_found = true;
                    }
                // 如果在库中查找到对应的Section Parser工具
                } else if (section_parser) {
                    // 调用解析工具的ParseLineSection来解析对应的一行
                    if (auto result = section_parser->ParseLineSection(std::move(args), state.line);
                        !result.ok()) {
                        parse_error_count_++;
                        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                    }
                // else
                } else if (!bad_section_found) {
                    parse_error_count_++;
                    LOG(ERROR) << filename << ": " << state.line
                               << ": Invalid section keyword found";
                }
                args.clear();
                break;
            }
            // 如果是TEXT文本,则直接添加其为参数
            case T_TEXT:
                args.emplace_back(state.text);
                break;
        }
    }
}

如上述代码可知,此处

首先,给对应的配置数据添加结束符,以防访问到内存中其他的数据

其次,将配置文件数据使用parse_state结构体来操作

struct parse_state
{
    char *ptr; // 此处的state的ptr指向配置文件数据的首字符
    char *text; // 默认数据
    int line;   // 默认为0
    int nexttoken; // 默认为0
};

再次,定义一个end_section函数引用,这个函数的主要作用是,若section_parser不为空,则调用其EndSection函数,做一些结束解析工作。

最后,通过一个循环,来一点点地解析配置文件数据

接下来,我们来开始解析对应的配置文件数据

循环中,是一个switch语句,switch的主体是next_token函数,参数为上述定义的parse_state对象引用

int next_token(struct parse_state *state)
{
    char *x = state->ptr;
    char *s;
 
    if (state->nexttoken) {
        int t = state->nexttoken;
        state->nexttoken = 0;
        return t;
    }
 
    for (;;) {
        switch (*x) {
        case 0:
            state->ptr = x;
            return T_EOF;
        case '\n':
            x++;
            state->ptr = x;
            return T_NEWLINE;
        case ' ':
        case '\t':
        case '\r':
            x++;
            continue;
        case '#':
            while (*x && (*x != '\n')) x++;
            if (*x == '\n') {
                state->ptr = x+1;
                return T_NEWLINE;
            } else {
                state->ptr = x;
                return T_EOF;
            }
        default:
            goto text;
        }
    }
textdone:
    state->ptr = x;
    *s = 0;
    return T_TEXT;
text:
    state->text = s = x;
textresume:
    for (;;) {
        switch (*x) {
        case 0:
            goto textdone;
        case ' ':
        case '\t':
        case '\r':
            x++;
            goto textdone;
        case '\n':
            state->nexttoken = T_NEWLINE;
            x++;
            goto textdone;
        case '"':
            x++;
            for (;;) {
                switch (*x) {
                case 0:
                    /* unterminated quoted thing */
                    state->ptr = x;
                    return T_EOF;
                case '"':
                    x++;
                    goto textresume;
                default:
                    *s++ = *x++;
                }
            }
            break;
        case '\\':
            x++;
            switch (*x) {
            case 0:
                goto textdone;
            case 'n':
                *s++ = '\n';
                x++;
                break;
            case 'r':
                *s++ = '\r';
                x++;
                break;
            case 't':
                *s++ = '\t';
                x++;
                break;
            case '\\':
                *s++ = '\\';
                x++;
                break;
            case '\r':
                /* \ <cr> <lf> -> line continuation */
                if (x[1] != '\n') {
                    x++;
                    continue;
                }
                x++;
                FALLTHROUGH_INTENDED;
            case '\n':
                /* \ <lf> -> line continuation */
                state->line++;
                x++;
                /* eat any extra whitespace */
                while((*x == ' ') || (*x == '\t')) x++;
                continue;
            default:
                /* unknown escape -- just copy */
                *s++ = *x++;
            }
            continue;
        default:
            *s++ = *x++;
        }
    }
    return T_EOF;
}

可以看到,这个next_token函数,主要工作如下

若当前state->ptr指向的字符为大写字母或者小写字母,则保存此字符为继续指向下一个字符,并解析,直至解析出一个非字母的字符,最终将上述全部解析的字母使用state->text指向其首部,然后返回T_TEXT

若当前为换行符’\n’,则表明此时上一行已经解析完成,将state->ptr指向当前的后一个位置,并且返回T_NEWLINE

若当前为空格符、’\t’、’\r’等,则继续解析下一个字符

若当前字符为’#’,则过滤该行数据,当然,若最终解析的最后一个字符为’\n’,则返回T_NEWLINE,若不是,则表明配置文件数据已经解析完成,则直接返回T_EOF

那么,再回到ParseData的for循环中

当next_token函数返回的为T_EOF,表明配置文件已经解析完成,此处会调用所有的解析工具(此处为上述通过AddSectionParser添加的三个工具)的EndSection来结束解析

当next_token函数返回的是T_NEWLINE,则获取对应的args中的所有数据进行响应的操作,那么args中的数据从哪儿来的呢?看下面的解析

当next_token函数返回的是T_TEXT,则将返回回来的对应字符串添加到args字符串数组中

因此,综合上述ParseData的解析过程,可知,此处是按行解析,若解析到字符串的时候,则将其添加到args字符串数组中,然后当该行解析完成时,则交由T_NEWLINE对应的操作来解析,若配置数据解析完成后,则交由T_EOF对应的操作来处理

接下来,我们就来看下,如下的三个解析工具具体的解析工作。

ServiceParser解析工具

初始化

从上述代码看,ServiceParser的初始化语句如下

std::make_unique<ServiceParser>(&service_list, GetSubcontext(), std::nullopt)

而ServiceParser的构造函数如下

ServiceParser(ServiceList* service_list, Subcontext* subcontext,
            const std::optional<InterfaceInheritanceHierarchyMap>& interface_inheritance_hierarchy,
            bool from_apex = false)
        : service_list_(service_list),
          subcontext_(subcontext),
          interface_inheritance_hierarchy_(interface_inheritance_hierarchy),
          service_(nullptr),
          from_apex_(from_apex) {}

也即,此处将ServiceParser对象的

名称为service_list_的ServiceList对象引用指向刚刚创建的ServiceList对象,

名称为subcontext_的Subcontext对象引用指向前文的Subcontext对象,

名称为interface_inheritance_hierarchy_为nullopt,

名称为service_的Service对象指向nullptr

from_apex_设定为false

解析流程

在ServiceParser解析器解析的过程中,肯定需要一个配置文件进行配合,那么我们就使用经典的zygote配置文件来解析一遍吧,此处我们使用init.zygote32.rc配置文件

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    task_profiles ProcessCapacityHigh
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

通过Parser的ParseData函数分析可知,配置文件的解析是按行解析,因此此处,首先会读取第一行的所有内容,然后遇到字符串,则将其添加到args中,然后一行解析完成后,则在T_NEWLINE中处理,因此,我们一行行地分析

第一行

首先来看第一行

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

经过上述的分析,此处最开始由于是有字母(包含’/’字符、’-’)组成,因此会将所有的字符串加入到args字符串数组中

也就是在遇到最后的’\n’时,args中的数据如下

{
    “service”,
    “zygote”,
    “/system/bin/app_process”,
    “-Xzygote”,
    “/system/bin”,
    “--zygote”,
    “—start-system-server”
}

接下来是换行符,即返回T_NEWLINE

case T_NEWLINE: {
    // 确认解析行数
    state.line++;
    // 如果args为空,则无需解析
    if (args.empty()) break;
    // If we have a line matching a prefix we recognize, call its callback and unset any
    // current section parsers.  This is meant for /sys/ and /dev/ line entries for
    // uevent.
    // 从字符串中查找以args[0]开头的对应的子字符串
    // 此处由于line_callbacks为定义,因此此处无法查出对应的line_callback
    auto line_callback = std::find_if(
        line_callbacks_.begin(), line_callbacks_.end(),
        [&args](const auto& c) { return android::base::StartsWith(args[0], c.first); });
    if (line_callback != line_callbacks_.end()) {
        // 关闭section解析工具
        end_section();
       
        if (auto result = line_callback->second(std::move(args)); !result.ok()) {
            parse_error_count_++;
            LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
        }
    // 通过args[0]字符串来判断对应的map中是否有args[0]对应的解析工具
    } else if (section_parsers_.count(args[0])) {
        end_section();
        // 获取解析工具
        section_parser = section_parsers_[args[0]].get();
        section_start_line = state.line;
        // 解析Section
        if (auto result =
                    section_parser->ParseSection(std::move(args), filename, state.line);
            !result.ok()) {
            parse_error_count_++;
            LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
            section_parser = nullptr;
            bad_section_found = true;
        }
    // 如果当前的args[0]没有找到对应的解析工具,则判断解析工具是否已经存在
    } else if (section_parser) {
         // 调用解析工具的ParseLineSection来解析对应的一行
        if (auto result = section_parser->ParseLineSection(std::move(args), state.line);
            !result.ok()) {
            parse_error_count_++;
            LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
        }
    // 上述条件均不满足,则打印当前行无法解析的日志
    } else if (!bad_section_found) {
        parse_error_count_++;
        LOG(ERROR) << filename << ": " << state.line
                   << ": Invalid section keyword found";
}
// 最后将args清空,以便下一行解析
    args.clear();
    break;
}

如果上述代码,由于args[0]为”service”字符串,因此在section_parser_的map中找到其对应的是ServiceParser解析工具,因此section_parser设定为ServiceParser工具,此后调用该工具的ParseSection函数

Result<void> ServiceParser::ParseSection(std::vector<std::string>&& args,
                                         const std::string& filename, int line) {
    // 此处args的个数为7个,不满足条件
    if (args.size() < 3) {
        return Error() << "services must have a name and a program";
    }
    // 获取对应的name为”zygote”
    const std::string& name = args[1];
    // 判断名称是否合法
    if (!IsValidName(name)) {
        return Error() << "invalid service name '" << name << "'";
    }
    // 文件路径设定
    filename_ = filename;
 
    Subcontext* restart_action_subcontext = nullptr;
    // 判断是否是/vendor下的或者/odm下的配置文件解析,此处不是
    if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
        restart_action_subcontext = subcontext_;
    }
 
    // 获取args的后五个参数
    std::vector<std::string> str_args(args.begin() + 2, args.end());
    ......
    // 初始化一个名称为service_的Service对象
    service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args, from_apex_);
    return {};
}

从上述的代码可以看到,这段代码主要是创建了一个Service对象,并且初始化service_指向该对象引用

Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
                 const std::vector<std::string>& args, bool from_apex)
    : Service(name, 0, 0, 0, {}, 0, "", subcontext_for_restart_commands, args, from_apex) {}

Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
                 const std::vector<gid_t>& supp_gids, int namespace_flags,
                 const std::string& seclabel, Subcontext* subcontext_for_restart_commands,
                 const std::vector<std::string>& args, bool from_apex)
    : name_(name),
      classnames_({"default"}),
      flags_(flags),
      pid_(0),
      crash_count_(0),
      proc_attr_{.ioprio_class = IoSchedClass_NONE,
                 .ioprio_pri = 0,
                 .uid = uid,
                 .gid = gid,
                 .supp_gids = supp_gids,
                 .priority = 0},
      namespaces_{.flags = namespace_flags},
      seclabel_(seclabel),
      subcontext_(subcontext_for_restart_commands),
      onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0,
                 "onrestart", {}),
      oom_score_adjust_(DEFAULT_OOM_SCORE_ADJUST),
      start_order_(0),
      args_(args),
      from_apex_(from_apex) {}

根据其构造函数,此处主要设置其name_为zygote,args_为上述读取的最后五个参数数组,即

{
    “/system/bin/app_process”,
    “-Xzygote”,
    “/system/bin”,
    “--zygote”,
    “—start-system-server”
}

第二行

接下来解析第二行

class main

由上述分析可知,此处会解析出args包含两个字符串参数,即”class”和”main”

然后进入T_NEWLINE,此时由于class无对应的解析工具,且section_parser已经设定为ServiceParser,因此调用ServiceParser的ParseLineSection函数

Result<void> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {
    // 前一行解析的时候已经创建
    if (!service_) {
        return {};
    }

    // 从GetParserMap中获取解析工具(对应解析方法)
    auto parser = GetParserMap().Find(args);
    if (!parser.ok()) return parser.error();
    // 获取到对应的解析方法后,调用它
    return std::invoke(*parser, this, std::move(args));
}

从上述代码分析,获取对应的解析方法再调用它

const KeywordMap<ServiceParser::OptionParser>& ServiceParser::GetParserMap() const {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    // clang-format off
    static const KeywordMap<ServiceParser::OptionParser> parser_map = {
        {"capabilities",            {0,     kMax, &ServiceParser::ParseCapabilities}},
        {"class",                   {1,     kMax, &ServiceParser::ParseClass}},
        {"console",                 {0,     1,    &ServiceParser::ParseConsole}},
        {"critical",                {0,     2,    &ServiceParser::ParseCritical}},
        {"disabled",                {0,     0,    &ServiceParser::ParseDisabled}},
        {"enter_namespace",         {2,     2,    &ServiceParser::ParseEnterNamespace}},
        {"file",                    {2,     2,    &ServiceParser::ParseFile}},
        {"group",                   {1,     NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}},
        {"interface",               {2,     2,    &ServiceParser::ParseInterface}},
        {"ioprio",                  {2,     2,    &ServiceParser::ParseIoprio}},
        {"keycodes",                {1,     kMax, &ServiceParser::ParseKeycodes}},
        {"memcg.limit_in_bytes",    {1,     1,    &ServiceParser::ParseMemcgLimitInBytes}},
        {"memcg.limit_percent",     {1,     1,    &ServiceParser::ParseMemcgLimitPercent}},
        {"memcg.limit_property",    {1,     1,    &ServiceParser::ParseMemcgLimitProperty}},
        {"memcg.soft_limit_in_bytes",
                                    {1,     1,    &ServiceParser::ParseMemcgSoftLimitInBytes}},
        {"memcg.swappiness",        {1,     1,    &ServiceParser::ParseMemcgSwappiness}},
        {"namespace",               {1,     2,    &ServiceParser::ParseNamespace}},
        {"oneshot",                 {0,     0,    &ServiceParser::ParseOneshot}},
        {"onrestart",               {1,     kMax, &ServiceParser::ParseOnrestart}},
        {"oom_score_adjust",        {1,     1,    &ServiceParser::ParseOomScoreAdjust}},
        {"override",                {0,     0,    &ServiceParser::ParseOverride}},
        {"priority",                {1,     1,    &ServiceParser::ParsePriority}},
        {"reboot_on_failure",       {1,     1,    &ServiceParser::ParseRebootOnFailure}},
        {"restart_period",          {1,     1,    &ServiceParser::ParseRestartPeriod}},
        {"rlimit",                  {3,     3,    &ServiceParser::ParseProcessRlimit}},
        {"seclabel",                {1,     1,    &ServiceParser::ParseSeclabel}},
        {"setenv",                  {2,     2,    &ServiceParser::ParseSetenv}},
        {"shutdown",                {1,     1,    &ServiceParser::ParseShutdown}},
        {"sigstop",                 {0,     0,    &ServiceParser::ParseSigstop}},
        {"socket",                  {3,     6,    &ServiceParser::ParseSocket}},
        {"stdio_to_kmsg",           {0,     0,    &ServiceParser::ParseStdioToKmsg}},
        {"task_profiles",           {1,     kMax, &ServiceParser::ParseTaskProfiles}},
        {"timeout_period",          {1,     1,    &ServiceParser::ParseTimeoutPeriod}},
        {"updatable",               {0,     0,    &ServiceParser::ParseUpdatable}},
        {"user",                    {1,     1,    &ServiceParser::ParseUser}},
        {"writepid",                {1,     kMax, &ServiceParser::ParseWritepid}},
    };
    // clang-format on
    return parser_map;
}

可以看到,class字符串对应的解析函数为ServiceParser::ParseClass

Result<void> ServiceParser::ParseClass(std::vector<std::string>&& args) {
    service_->classnames_ = std::set<std::string>(args.begin() + 1, args.end());
    return {};
}

此处设置service_对应引用的classnames_字段为args的第二个参数,即main

第三行

接下来,第三行

priority -20

根据上述分析,此处调用ServiceParser::ParsePriority函数引用

Result<void> ServiceParser::ParsePriority(std::vector<std::string>&& args) {
    service_->proc_attr_.priority = 0;
    if (!ParseInt(args[1], &service_->proc_attr_.priority,
                  static_cast<int>(ANDROID_PRIORITY_HIGHEST),  // highest is negative
                  static_cast<int>(ANDROID_PRIORITY_LOWEST))) {
        return Errorf("process priority value must be range {} - {}", ANDROID_PRIORITY_HIGHEST,
                      ANDROID_PRIORITY_LOWEST);
    }
    return {};
}

可知,设定service_->proc_attr_.priority为-20,最高优先级

第四行

接下来

user root

根据上述分析,调用&ServiceParser::ParseUser函数

Result<void> ServiceParser::ParseUser(std::vector<std::string>&& args) {
    auto uid = DecodeUid(args[1]);
    if (!uid.ok()) {
        return Error() << "Unable to find UID for '" << args[1] << "': " << uid.error();
    }
    service_->proc_attr_.uid = *uid;
    return {};
}

设置对应的service_->proc_attr_.uid

第五行

接下来

group root readproc reserved_disk

根据此前分析,此处调用ServiceParser::ParseGroup

Result<void> ServiceParser::ParseGroup(std::vector<std::string>&& args) {
    // 解析gid
    auto gid = DecodeUid(args[1]);
    if (!gid.ok()) {
        return Error() << "Unable to decode GID for '" << args[1] << "': " << gid.error();
    }
    // 设置service_->proc_attr_.gid
    service_->proc_attr_.gid = *gid;

    for (std::size_t n = 2; n < args.size(); n++) {
        gid = DecodeUid(args[n]);
        if (!gid.ok()) {
            return Error() << "Unable to decode GID for '" << args[n] << "': " << gid.error();
        }
        // 解析对应的service_->proc_attr_.supp_gids
        service_->proc_attr_.supp_gids.emplace_back(*gid);
    }
    return {};
}

如上,解析对应的service_->proc_attr_.gid和service_->proc_attr_.supp_gids

第六-七行

接下来

socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system

同一个socket开头的字段,调用ServiceParser::ParseSocket

Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
    SocketDescriptor socket;
    // 设置socket的名称
    socket.name = std::move(args[1]);

    // 设置socket的type
    auto types = Split(args[2], "+");
    if (types[0] == "stream") {
        socket.type = SOCK_STREAM;
    } else if (types[0] == "dgram") {
        socket.type = SOCK_DGRAM;
    } else if (types[0] == "seqpacket") {
        socket.type = SOCK_SEQPACKET;
    } else {
        return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket', got '" << types[0]
                       << "' instead.";
    }

    if (types.size() > 1) {
        if (types.size() == 2 && types[1] == "passcred") {
            socket.passcred = true;
        } else {
            return Error() << "Only 'passcred' may be used to modify the socket type";
        }
    }
    errno = 0;
    
    char* end = nullptr;
    // socket.perm
    socket.perm = strtol(args[3].c_str(), &end, 8);
    if (errno != 0) {
        return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
    }
    if (end == args[3].c_str() || *end != '\0') {
        errno = EINVAL;
        return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
    }

    if (args.size() > 4) {
         // 解析socket.uid
        auto uid = DecodeUid(args[4]);
        if (!uid.ok()) {
            return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error();
        }
        socket.uid = *uid;
    }

    if (args.size() > 5) {
         // 解析socket.gid
        auto gid = DecodeUid(args[5]);
        if (!gid.ok()) {
            return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error();
        }
        socket.gid = *gid;
    }

    // 此处无第7个参数
    socket.context = args.size() > 6 ? args[6] : "";
    auto old = std::find_if(service_->sockets_.begin(), service_->sockets_.end(),
                            [&socket](const auto& other) { return socket.name == other.name; });
    if (old != service_->sockets_.end()) {
        return Error() << "duplicate socket descriptor '" << socket.name << "'";
    }
    service_->sockets_.emplace_back(std::move(socket));
    return {};
}

解析service_->sockets_

第八-十四行

onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond

由前述可致,调用ServiceParser::ParseOnrestart

Result<void> ServiceParser::ParseOnrestart(std::vector<std::string>&& args) {
    args.erase(args.begin());
    int line = service_->onrestart_.NumCommands() + 1;
        if (auto result = service_->onrestart_.AddCommand(std::move(args), line); !result.ok()) {
        return Error() << "cannot add Onrestart command: " << result.error();
    }
    return {};
}

添加命令行到service_->onrestart_中,onrestart_是一个Action对象

Result<void> Action::AddCommand(std::vector<std::string>&& args, int line) {
    if (!function_map_) {
        return Error() << "no function map available";
    }

    auto map_result = function_map_->Find(args);
    if (!map_result.ok()) {
        return Error() << map_result.error();
    }
    commands_.emplace_back(map_result->function, map_result->run_in_subcontext, std::move(args),
                           line);
    return {};
}

即,将对应的操作函数添加到对应的service_->onrestart_->commands_中,此问题后续再行分析

第十五行

task_profiles ProcessCapacityHigh

同样地,调用ServiceParser::ParseTaskProfiles

Result<void> ServiceParser::ParseTaskProfiles(std::vector<std::string>&& args) {
    args.erase(args.begin());
    service_->task_profiles_ = std::move(args);
    return {};
}

设置service_->task_profiles_参数

第十六行

critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

调用ServiceParser::ParseCritical

Result<void> ServiceParser::ParseCritical(std::vector<std::string>&& args) {
    std::optional<std::string> fatal_reboot_target;
    std::optional<std::chrono::minutes> fatal_crash_window;
 
    for (auto it = args.begin() + 1; it != args.end(); ++it) {
        auto arg = android::base::Split(*it, "=");
        if (arg.size() != 2) {
            return Error() << "critical: Argument '" << *it << "' is not supported";
         // 第二个参数为target
        } else if (arg[0] == "target") {
           // 设置fatal_reboot_target为”zygote-fatal”
            fatal_reboot_target = arg[1];
        // 第一个参数为windows,解析zygote.critical_window.minute为off,并设置属性值
        } else if (arg[0] == "window") {
            int minutes;
            auto window = ExpandProps(arg[1]);
            if (!window.ok()) {
                return Error() << "critical: Could not expand argument ': " << arg[1];
            }
           // 此处直接返回
            if (*window == "off") {
                return {};
            }
            if (!ParseInt(*window, &minutes, 0)) {
                return Error() << "critical: 'fatal_crash_window' must be an integer > 0";
            }
            fatal_crash_window = std::chrono::minutes(minutes);
        } else {
            return Error() << "critical: Argument '" << *it << "' is not supported";
        }
    }
    if (fatal_reboot_target) {
        service_->fatal_reboot_target_ = *fatal_reboot_target;
    }
    if (fatal_crash_window) {
        service_->fatal_crash_window_ = *fatal_crash_window;
    }
    service_->flags_ |= SVC_CRITICAL;
    return {};
}

设置service_->fatal_reboot_target_为”zygote-fatal”

结束

最后会调用结束时会返回一个T_EOF,会调用ServiceParser的EndSection函数(由于ServiceParser未定义EndFile函数,无需分析)

Result<void> ServiceParser::EndSection() {
    ......
    // 查找是否已经有包含对应的Service对象,此处由于是第一次添加,service_list_中肯定是没有的
    Service* old_service = service_list_->FindService(service_->name());
    if (old_service) {
        ......
    }
    // 将刚刚创建的Service对象,通过AddService保存到ServiceManager中
    service_list_->AddService(std::move(service_));
    return {};
}

可以看到,最终将将刚刚创建的Service对象,通过AddService保存到ServiceManager

void ServiceList::AddService(std::unique_ptr<Service> service) {
    services_.emplace_back(std::move(service));
}

即保存在Service的service_数组中

结论

ServiceParser解析工具解析配置文件,会将对应的配置文件的数据解析成一个Service对象,然后将其添加到ServiceManager中进行管理

ActionParser解析工具

初始化

根据前述,ActionParser的初始化如下

此处需要注意的是,ActionParser在map中的对应的字段为”on”

std::make_unique<ActionParser>(&action_manager, GetSubcontext())

对应的ActionParser构造函数

ActionParser(ActionManager* action_manager, Subcontext* subcontext)
        : action_manager_(action_manager), subcontext_(subcontext), action_(nullptr) {}

可以看到,此处主要是给ActionParser对象中参数赋值

解析流程

解析流程,需要有一个解析文件来配合解析,此处,我们看下init.usb.rc配置文件的内容,查看init.usb.rc配置文件的内容,此处我们仅看前一段的数据解析

on post-fs-data
    chown system system /sys/class/android_usb/android0/f_mass_storage/lun/file
    chmod 0660 /sys/class/android_usb/android0/f_mass_storage/lun/file
    chown system system /sys/class/android_usb/android0/f_rndis/ethaddr
    chmod 0660 /sys/class/android_usb/android0/f_rndis/ethaddr
    mkdir /data/misc/adb 02750 system shell
    mkdir /data/adb 0700 root root encryption=Require
 
# adbd is controlled via property triggers in init.<platform>.usb.rc
service adbd /system/bin/adbd --root_seclabel=u:r:su:s0
    class core
    socket adbd seqpacket 660 system system
    disabled
    updatable
    seclabel u:r:adbd:s0

on property:vendor.sys.usb.adb.disabled=*
    setprop sys.usb.adb.disabled ${vendor.sys.usb.adb.disabled}

# Set default value on sys.usb.configfs early in boot sequence. It will be
# overridden in `on boot` action of init.hardware.rc.
on init
setprop sys.usb.configfs 0
......

根据此前的分析,Parser在解析的过程中,会按行解析,遇到字母字符,则将对应的字符串存入到args字符串数组中,那么对于init.usb.rc文件的

第一行

on post-fs-data

根据此前的分析Parser解析到这一行的时候,会将上述两个字符串分别放入到args字符串数组中,然后通过第一个字符串”on”找到此处的解析工具ActionParser对象,并调用其ParseSection函数

Result<void> ActionParser::ParseSection(std::vector<std::string>&& args,
                                        const std::string& filename, int line) {
    // 将args数据存放到triggers字符串数组中,此处解析triggers中只有一个元素,即post-fs-data
    std::vector<std::string> triggers(args.begin() + 1, args.end());
    if (triggers.size() < 1) {
        return Error() << "Actions must have a trigger";
    }
 
    Subcontext* action_subcontext = nullptr;
    // 判断当前文件地址是否存在于/vendor或者/odm里,此处当然不是,则action_subcontext为nullptr
    if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
        action_subcontext = subcontext_;
    }
    std::string event_trigger;
    std::map<std::string, std::string> property_triggers;
    // 调用ParseTriggers函数
    if (auto result =
                ParseTriggers(triggers, action_subcontext, &event_trigger, &property_triggers);
        !result.ok()) {
        return Error() << "ParseTriggers() failed: " << result.error();
    }
    // 初始化一个Action对象
    auto action = std::make_unique<Action>(false, action_subcontext, filename, line, event_trigger,
                                           property_triggers);
    // 最后设置action_为刚刚创建的Action
    action_ = std::move(action);
    return {};
}

由上述代码可以看到,这边

首先调用了ActionParser的ParseTriggers函数

Result<void> ParseTriggers(const std::vector<std::string>& args, Subcontext* subcontext,
                           std::string* event_trigger,
                           std::map<std::string, std::string>* property_triggers) {
    const static std::string prop_str("property:");
    // for循环查看每一个传入的参数
    for (std::size_t i = 0; i < args.size(); ++i) {
        // 判断是否为空
        if (args[i].empty()) {
            return Error() << "empty trigger is not valid";
        }
        // 判断是否有两个参数
        if (i % 2) {
            if (args[i] != "&&") {
                return Error() << "&& is the only symbol allowed to concatenate actions";
            } else {
                continue;
            }
        }
        // 判断是否参数是否为property:开头的数据
        if (!args[i].compare(0, prop_str.length(), prop_str)) {
            if (auto result = ParsePropertyTrigger(args[i], subcontext, property_triggers);
                !result.ok()) {
                return result;
            }
        } else {
            if (!event_trigger->empty()) {
                return Error() << "multiple event triggers are not allowed";
            }
            // 判断传入参数是否为合法的事件触发器
            if (auto result = ValidateEventTrigger(args[i]); !result.ok()) {
                return result;
            }
            // 保存事件触发器
            *event_trigger = args[i];
        }
    }
    return {};
}

从上述可知,在此处,主要是让event_trigger指向args[0]所代表的数据,即post-fs-data

其次初始化了一个Action对象

Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line,
               const std::string& event_trigger,
               const std::map<std::string, std::string>& property_triggers)
    : property_triggers_(property_triggers),
      event_trigger_(event_trigger),
      oneshot_(oneshot),
      subcontext_(subcontext),
      filename_(filename),
      line_(line) {}

从传入参数来看,此处主要给Action的各项参数赋值

Oneshot_赋值为false

event_trigger_赋值为刚刚传入的字符串地址,其数值为post-fs-data

subcontext_赋值为前文中初始化的Subcontext对象

filename_为配置文件地址

line_表明这是第几行

第二行

chown system system /sys/class/android_usb/android0/f_mass_storage/lun/file

解析这一句话,此处我们知道chown没有对应的解析工具,而刚刚在第一行解析的时候,已经设置了section_parser对象为ActionParser对象,因此此处调用ActionParser的ParseLineSection函数,其参数为上述的各项字符串

Result<void> ActionParser::ParseLineSection(std::vector<std::string>&& args, int line) {
    return action_ ? action_->AddCommand(std::move(args), line) : Result<void>{};
}

此前可知action_我们刚刚已经创建了,因此此处调用其AddCommand函数

Result<void> Action::AddCommand(std::vector<std::string>&& args, int line) {
    if (!function_map_) {
        return Error() << "no function map available";
    }
    // 从function_map_中查找参数所对应的函数
    auto map_result = function_map_->Find(args);
    // 若未找到对应的解析函数,则直接退出
    if (!map_result.ok()) {
        return Error() << map_result.error();
    }
    // 将对应的函数,以及参数存放到对应的命令行数组中
    commands_.emplace_back(map_result->function, map_result->run_in_subcontext, std::move(args),
                           line);
    return {};
}

这段代码可知,主要是将此处的命令加入到Action的命令行数组中,那么function_map是什么?这个在系统启动的过程中,有通过Action::set_function_map设置过,我们重温一下这个map

// Builtin-function-map start
const BuiltinFunctionMap& GetBuiltinFunctionMap() {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    // clang-format off
    static const BuiltinFunctionMap builtin_functions = {
        {"bootchart",               {1,     1,    {false,  do_bootchart}}},
        {"chmod",                   {2,     2,    {true,   do_chmod}}},
        {"chown",                   {2,     3,    {true,   do_chown}}},
        {"class_reset",             {1,     1,    {false,  do_class_reset}}},
        {"class_reset_post_data",   {1,     1,    {false,  do_class_reset_post_data}}},
        {"class_restart",           {1,     1,    {false,  do_class_restart}}},
        {"class_start",             {1,     1,    {false,  do_class_start}}},
        {"class_start_post_data",   {1,     1,    {false,  do_class_start_post_data}}},
        {"class_stop",              {1,     1,    {false,  do_class_stop}}},
        {"copy",                    {2,     2,    {true,   do_copy}}},
        {"copy_per_line",           {2,     2,    {true,   do_copy_per_line}}},
        {"domainname",              {1,     1,    {true,   do_domainname}}},
        {"enable",                  {1,     1,    {false,  do_enable}}},
        {"exec",                    {1,     kMax, {false,  do_exec}}},
        {"exec_background",         {1,     kMax, {false,  do_exec_background}}},
        {"exec_start",              {1,     1,    {false,  do_exec_start}}},
        {"export",                  {2,     2,    {false,  do_export}}},
        {"hostname",                {1,     1,    {true,   do_hostname}}},
        {"ifup",                    {1,     1,    {true,   do_ifup}}},
        {"init_user0",              {0,     0,    {false,  do_init_user0}}},
        {"insmod",                  {1,     kMax, {true,   do_insmod}}},
        {"installkey",              {1,     1,    {false,  do_installkey}}},
        {"interface_restart",       {1,     1,    {false,  do_interface_restart}}},
        {"interface_start",         {1,     1,    {false,  do_interface_start}}},
        {"interface_stop",          {1,     1,    {false,  do_interface_stop}}},
        {"load_exports",            {1,     1,    {false,  do_load_exports}}},
        {"load_persist_props",      {0,     0,    {false,  do_load_persist_props}}},
        {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
        {"loglevel",                {1,     1,    {false,  do_loglevel}}},
        {"mark_post_data",          {0,     0,    {false,  do_mark_post_data}}},
        {"mkdir",                   {1,     6,    {true,   do_mkdir}}},
        // TODO: Do mount operations in vendor_init.
        // mount_all is currently too complex to run in vendor_init as it queues action triggers,
        // imports rc scripts, etc.  It should be simplified and run in vendor_init context.
        // mount and umount are run in the same context as mount_all for symmetry.
        {"mount_all",               {0,     kMax, {false,  do_mount_all}}},
        {"mount",                   {3,     kMax, {false,  do_mount}}},
        {"perform_apex_config",     {0,     0,    {false,  do_perform_apex_config}}},
        {"umount",                  {1,     1,    {false,  do_umount}}},
        {"umount_all",              {0,     1,    {false,  do_umount_all}}},
        {"update_linker_config",    {0,     0,    {false,  do_update_linker_config}}},
        {"readahead",               {1,     2,    {true,   do_readahead}}},
        {"remount_userdata",        {0,     0,    {false,  do_remount_userdata}}},
        {"restart",                 {1,     1,    {false,  do_restart}}},
        {"restorecon",              {1,     kMax, {true,   do_restorecon}}},
        {"restorecon_recursive",    {1,     kMax, {true,   do_restorecon_recursive}}},
        {"rm",                      {1,     1,    {true,   do_rm}}},
        {"rmdir",                   {1,     1,    {true,   do_rmdir}}},
        {"setprop",                 {2,     2,    {true,   do_setprop}}},
        {"setrlimit",               {3,     3,    {false,  do_setrlimit}}},
        {"start",                   {1,     1,    {false,  do_start}}},
        {"stop",                    {1,     1,    {false,  do_stop}}},
        {"swapon_all",              {0,     1,    {false,  do_swapon_all}}},
        {"enter_default_mount_ns",  {0,     0,    {false,  do_enter_default_mount_ns}}},
        {"symlink",                 {2,     2,    {true,   do_symlink}}},
        {"sysclktz",                {1,     1,    {false,  do_sysclktz}}},
        {"trigger",                 {1,     1,    {false,  do_trigger}}},
        {"verity_update_state",     {0,     0,    {false,  do_verity_update_state}}},
        {"wait",                    {1,     2,    {true,   do_wait}}},
        {"wait_for_prop",           {2,     2,    {false,  do_wait_for_prop}}},
        {"write",                   {2,     2,    {true,   do_write}}},
    };
    // clang-format on
    return builtin_functions;
}

从这个map中,我们可以找到对应的chown的运行函数为do_chown函数,此处我们不做过多解析,通过名称可知,这是改变文件权限的

第三-七行

通过上述对于第二行的解析可以看到,此处会给Aciton对象的commands_命令行数组中添加一些命令

第十-十五行

通过此前对于ServiceParser的解析可知,此处主要创建一个Service对象,然后添加到ServiceManager中进行管理

但是,在此处,由于此前ActionParser在解析的过程中没有遇到T_EOF,那么对应的Action对象是如何来保存的呢?

这个就用到此前分析过的end_section函数,这个函数我们此前分析过,主要是当遇到T_EOF的时候或者当遇到下一个SectionParser的时候,会调用到它,且在这个函数中,主要是调用了对应的section_parser的EndSection函数,那么对于init.usb.rc文件来说,遇到下一个ServiceParser之前,会调用ActionParser::EndSection

Result<void> ActionParser::EndSection() {
    if (action_ && action_->NumCommands() > 0) {
        action_manager_->AddAction(std::move(action_));
    }
    return {};
}

也即,将在第一行中创建的Action对象添加到ActionManager中进行管理

void ActionManager::AddAction(std::unique_ptr<Action> action) {
    actions_.emplace_back(std::move(action));
}

可以看到,此处将Action对象添加到ActionManager的action_参数数组中

第十七-十八行

on property:vendor.sys.usb.adb.disabled=*
    setprop sys.usb.adb.disabled ${vendor.sys.usb.adb.disabled}

此处与第一行的Action解析不同的地方在于ParserTriggers中,由于此处解析的args是以property:开头,因此会调用ParsePropertyTrigger函数

Result<void> ParsePropertyTrigger(const std::string& trigger, Subcontext* subcontext,
                                  std::map<std::string, std::string>* property_triggers) {
    const static std::string prop_str("property:");
    // 获取proterty:后续的字符串
    std::string prop_name(trigger.substr(prop_str.length()));
    // 判断字符串中是否有包含’=’字符
    size_t equal_pos = prop_name.find('=');
    if (equal_pos == std::string::npos) {
        return Error() << "property trigger found without matching '='";
    }
    // 解析属性值名称为vendor.sys.usb.adb.disabled,属性值为*
    std::string prop_value(prop_name.substr(equal_pos + 1));
    prop_name.erase(equal_pos);
    // 由于此属性值名称以vendor开头,因此此处函数返回true
    if (!IsActionableProperty(subcontext, prop_name)) {
        return Error() << "unexported property trigger found: " << prop_name;
    }
    // 将成对的属性保存到property_triggers中
        if (auto [it, inserted] = property_triggers->emplace(prop_name, prop_value); !inserted) {
        return Error() << "multiple property triggers found for same property";
    }
    return {};
}

然后创建Action对象,表明此行动项是以属性来触发,然后继续解析下一行,添加该行动项的命令行,最终,同上述解析一样,添加到ActionManager的action_行动项数组中

结论

触发ActionParser解析工具,则会解析出一个Action对象,这个Action包含很多的command,最后将这个Action对象添加到ActionManager

ImportParser解析工具

初始化

std::make_unique<ImportParser>(&parser)

直接初始化一个ImportParser对象

ImportParser(Parser* parser) : parser_(parser) {}

解析流程

这个我们使用init.rc文件来看下

import /init.environ.rc
import /system/etc/init/hw/init.usb.rc
import /init.${ro.hardware}.rc

在解析过程中,由前述可知,第一行,会触发ImportParser的ParserSection函数

Result<void> ImportParser::ParseSection(std::vector<std::string>&& args,
                                        const std::string& filename, int line) {
    if (args.size() != 2) {
        return Error() << "single argument needed for import\n";
    }
    // 解析第二个参数
    auto conf_file = ExpandProps(args[1]);
    if (!conf_file.ok()) {
        return Error() << "Could not expand import: " << conf_file.error();
    }
    LOG(INFO) << "Added '" << *conf_file << "' to import list";
    if (filename_.empty()) filename_ = filename;
    // 添加到imports_中
    imports_.emplace_back(std::move(*conf_file), line);
    return {};
}

首先解析第一个参数

Result<std::string> ExpandProps(const std::string& src) {
    const char* src_ptr = src.c_str();
    std::string dst;
    /* - variables can either be $x.y or ${x.y}, in case they are only part
     *   of the string.
     * - will accept $$ as a literal $.
     * - no nested property expansion, i.e. ${foo.${bar}} is not supported,
     *   bad things will happen
     * - ${x.y:-default} will return default value if property empty.
     */
    while (*src_ptr) {
        const char* c;
        c = strchr(src_ptr, '$');
        if (!c) {
            dst.append(src_ptr);
            return dst;
        }
        dst.append(src_ptr, c);
        c++;
        if (*c == '$') {
            dst.push_back(*(c++));
            src_ptr = c;
            continue;
        } else if (*c == '\0') {
            return dst;
        }
        std::string prop_name;
        std::string def_val;
        if (*c == '{') {
            c++;
            const char* end = strchr(c, '}');
            if (!end) {
                // failed to find closing brace, abort.
                return Error() << "unexpected end of string in '" << src << "', looking for }";
            }
            prop_name = std::string(c, end);
            c = end + 1;
            size_t def = prop_name.find(":-");
            if (def < prop_name.size()) {
                def_val = prop_name.substr(def + 2);
                prop_name = prop_name.substr(0, def);
            }
        } else {
            prop_name = c;
            if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) {
                return Error() << "using deprecated syntax for specifying property '" << c
                               << "', use ${name} instead";
            } else {
                LOG(ERROR) << "using deprecated syntax for specifying property '" << c
                           << "', use ${name} instead";
            }
            c += prop_name.size();
        }
        if (prop_name.empty()) {
            return Error() << "invalid zero-length property name in '" << src << "'";
        }
        std::string prop_val = android::base::GetProperty(prop_name, "");
        if (prop_val.empty()) {
            if (def_val.empty()) {
                return Error() << "property '" << prop_name << "' doesn't exist while expanding '"
                               << src << "'";
            }
            prop_val = def_val;
        }
        dst.append(prop_val);
        src_ptr = c;
    }
    return dst;
}

主要解析第二个参数文件地址中包含的属性名称对应的属性值,并替换到该字符串中 此后将所有import开头的配置数据均保存到import_数组中

那么在什么位置进行解析的呢? 还记得当配置文件解析完成的时候,会上报T_EOF给到Parser解析器么? 此时会调用所有配置文件解析工具的EndFile函数

void ImportParser::EndFile() {
    auto current_imports = std::move(imports_);
    imports_.clear();
    for (const auto& [import, line_num] : current_imports) {
        parser_->ParseConfig(import);
    }
}

然后将所有的imports_包含的配置文件地址重新使用Parser的ParseConfig解析一遍

由此,可知,import开始的行,init.rc中,虽然是在文件开始的时候就添加了这个行,但是知道配置文件解析结束后,才会一一重新解析这些import的配置文件

结论

ImportParser解析工具,从名称中就可以看出,这个解析工具,主要是添加一些引入一些其他解析文件,最后一起解析的

解析工具总结

从如上的三种解析工具的分析,我们可知,在解析配置文件的最后,会将这些配置文件变为

  1. Service对象,添加到ServiceList的service_服务数组中进行统一管理
  2. Action对象,添加到ActionManager的actions_行动项数组中进行统一管理,同时Action对象还包含了一个个的命令行,保存在commands_数组中
  3. ImportParser解析工具的主要作用是,引入一个新的配置文件