Android10 Framework—Init进程-13.rc文件解析

206 阅读14分钟

十年鹅厂程序员,专注大前端、AI、个人成长

Android系列文章目录

init进程的一个核心部分,是通过解析rc文件,执行Action和启动Service,配置文件解析相关代码如下:

//system/core/init/init.cpp

int SecondStageMain(int argc, char** argv) {
    ...省略代码 

    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);

    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();

    LoadBootScripts(am, sm);

    ...省略代码 
} 

首先这里创建了一个function_map,然后将其赋值给Action对象的function_map_变量;那么function_map是什么呢,它其实是个工具类

//system/core/init/keyword_map.h
class KeywordMap {
  public:
    using FunctionInfo = std::tuple<std::size_t, std::size_t, Function>;
    using Map = std::map<std::string, FunctionInfo>;

    virtual ~KeywordMap() {
    }

    const Result<Function> FindFunction(const std::vector<std::string>& args) const {
        using android::base::StringPrintf;

        if (args.empty()) return Error() << "Keyword needed, but not provided";

        auto& keyword = args[0];
        auto num_args = args.size() - 1;

        auto function_info_it = map().find(keyword);
        if (function_info_it == map().end()) {
            return Error() << StringPrintf("Invalid keyword '%s'", keyword.c_str());
        }

        auto function_info = function_info_it->second;

        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) {
            return Error() << StringPrintf("%s requires %zu argument%s", keyword.c_str(), min_args,
                                           (min_args > 1 || min_args == 0) ? "s" : "");
        }

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

        return std::get<Function>(function_info);
    }

  private:
    // Map of keyword ->
    // (minimum number of arguments, maximum number of arguments, function pointer)
    virtual const Map& map() const = 0;
};

//system/core/init/builtins.h
using KeywordFunctionMap = KeywordMap<std::pair<bool, BuiltinFunction>>;
class BuiltinFunctionMap : public KeywordFunctionMap {
  public:
    BuiltinFunctionMap() {}

  private:
    const Map& map() const override;
};

//system/core/init/service.cpp
class Service::OptionParserMap : public KeywordMap<OptionParser> {
  public:
    OptionParserMap() {}

  private:
    const Map& map() const override;
};

如下 2 个类比较重要

  • BuiltinFunctionMap
  • OptionParserMap

它们都继承KeywordMap,KeywordMap中FindFunction和map两个方法比较重要

  • FindFunction在KeywordMap中有实现,对于Action而言,FindFunction返回Action中commond对应功能实现函数;对Service而言,FindFunction返回Service中option对应解析函数
  • map的实现KeywordMap中,它根据Acton和Service不同,在各自实现中返回不同的函数描述

在这里将这些内容提前进行说明,后续会涉及到。

ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();

创建了用于管理从rc配置文件解析的Action和Service,实际的解析是调用LoadBootScripts开始进行的。

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);

    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        parser.ParseConfig("/init.rc");
        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
        if (!parser.ParseConfig("/product_services/etc/init")) {
            late_import_paths.emplace_back("/product_services/etc/init");
        }
        if (!parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if (!parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}

调用CreateParser构建解析器

Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser;

    parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));
    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontexts));
    parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));

    return parser;
}

这里实际上和前面讲的rc文件格式是对应的,三种关键字srvice、on、import都有其对应的解析器ServiceParser、ActionParser、ImportParser,其中ServiceParser、ActionParser分别又传入了service_list和action_manager。这三个都是section解析器,会被添加到section_parsers_变量中保存。

parser.ParseConfig("")

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

然后调用ParseConfig解析文件,可以看到其支持目录下遍历查找文件解析的,其中最重要的就是解析根目录下的/init.rc,我们以此作为主线进行分析

parser.ParseConfig("/init.rc");

bool Parser::ParseConfigFile(const std::string& path) {
    LOG(INFO) << "Parsing file " << path << "...";
    android::base::Timer t;
    auto config_contents = ReadFile(path);
    if (!config_contents) {
        LOG(INFO) << "Unable to read config file '" << path << "': " << config_contents.error();
        return false;
    }

    ParseData(path, &config_contents.value());

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

读取文件内容调用ParseData

void Parser::ParseData(const std::string& filename, std::string* data) {
    ...省略代码

    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.
                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();

                    if (auto result = line_callback->second(std::move(args)); !result) {
                        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;
                    if (auto result =
                            section_parser->ParseSection(std::move(args), filename, state.line);
                        !result) {
                        parse_error_count_++;
                        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                        section_parser = nullptr;
                        bad_section_found = true;
                    }
                } else if (section_parser) {
                    if (auto result = section_parser->ParseLineSection(std::move(args), state.line);
                        !result) {
                        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.clear();
                break;
            }
            case T_TEXT:
                args.emplace_back(state.text);
                break;
        }
    }
}

整个文本的解析是按section来解析的(以 import, on, service 开头的, 都表示一个 section(段落), 意味着一个关键词出现之后到出现第二个关键词 之前, 关键词后面的内容都属于一个 section)

  • T_NEWLINE:新行
  • T_TEXT:一行(除去关键字)中的参数
  • T_EOF:section结束

Action解析

以如下片段看看其解析流程

on early-init
    # Disable sysrq from keyboard
    write /proc/sys/kernel/sysrq 0

    # Set the security context of /adb_keys if present.
    restorecon /adb_keys

    # Set the security context of /postinstall if present.
    restorecon /postinstall

    mkdir /acct/uid

    # memory.pressure_level used by lmkd
    chown root system /dev/memcg/memory.pressure_level
    chmod 0040 /dev/memcg/memory.pressure_level
    # app mem cgroups, used by activity manager, lmkd and zygote
    mkdir /dev/memcg/apps/ 0755 system system
    # cgroup for system_server and surfaceflinger
    mkdir /dev/memcg/system 0550 system system

    start ueventd

    exec_start apexd-bootstrap

首先解析

on early-init

line_callback此时为空(后面会简单讲解一下line_callback),会执行如下代码

if (section_parsers_.count(args[0])) {
    end_section();
    section_parser = section_parsers_[args[0]].get();
    section_start_line = state.line;
    if (auto result =
            section_parser->ParseSection(std::move(args), filename, state.line);
        !result) {
        parse_error_count_++;
        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
        section_parser = nullptr;
        bad_section_found = true;
    }
}
  • 此时args[0]为字符串"on",因此获取的section解析器,这个解析器就是ActionParser
  • 当section_parser被赋值后,那就说明一个section要开始解析了
  • 调用ParseSection解析关键字on所在的行
//system/core/init/action_parser.cpp

Result<Success> ActionParser::ParseSection(std::vector<std::string>&& args,
                                           const std::string& filename, int line) {
    std::string event_trigger;
    std::map<std::string, std::string> property_triggers;

    if (auto result = ParseTriggers(triggers, action_subcontext, &event_trigger, &property_triggers);
        !result) {
        return Error() << "ParseTriggers() failed: " << result.error();
    }

    auto action = std::make_unique<Action>(false, action_subcontext, filename, line, event_trigger,
                                           property_triggers);

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

action的定义如下

on <trigger> [&& <trigger>]*
    <command>
    <command>
    <command>
  • trigger 作为触发器,trigger 有两种, event 和 proptery。

显然上面的代码将字符串中的event 和 proptery两种trigger解析到event_trigger和property_triggers变量中,然后创建一个Action对象,最后赋值给action_。

接下来继续解析command,因为section_parser变量已被赋值,则会调用如下代码进行command解析

if (section_parser) {
    if (auto result = section_parser->ParseLineSection(std::move(args), state.line);
        !result) {
        parse_error_count_++;
        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
    }
}


//system/core/init/action_parser.cpp
Result<Success> ActionParser::ParseLineSection(std::vector<std::string>&& args, int line) {
    return action_ ? action_->AddCommand(std::move(args), line) : Success();
}

ParseLineSection最终调用Action类的AddCommand

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

    auto function = function_map_->FindFunction(args);
    if (!function) return Error() << function.error();

    commands_.emplace_back(function->second, function->first, std::move(args), line);
    return Success();
}

FindFunction前面已经讲过是怎么来的了,其中调用了map方法,map方法实现如下

//system/core/init/builtins.cpp

const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    // clang-format off
    static const Map 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}}},
        {"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_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,     4,    {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",               {1,     kMax, {false,  do_mount_all}}},
        {"mount",                   {3,     kMax, {false,  do_mount}}},
        {"parse_apex_configs",      {0,     0,    {false,  do_parse_apex_configs}}},
        {"umount",                  {1,     1,    {false,  do_umount}}},
        {"umount_all",              {1,     1,    {false,  do_umount_all}}},
        {"readahead",               {1,     2,    {true,   do_readahead}}},
        {"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",              {1,     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_load_state",       {0,     0,    {false,  do_verity_load_state}}},
        {"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;
}

Action中所有commond命令都有其对应实现。

const Result<Function> FindFunction(const std::vector<std::string>& args) const {
        using android::base::StringPrintf;

        if (args.empty()) return Error() << "Keyword needed, but not provided";

        auto& keyword = args[0];
        auto num_args = args.size() - 1;

        auto function_info_it = map().find(keyword);
        if (function_info_it == map().end()) {
            return Error() << StringPrintf("Invalid keyword '%s'", keyword.c_str());
        }

        auto function_info = function_info_it->second;

        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) {
            return Error() << StringPrintf("%s requires %zu argument%s", keyword.c_str(), min_args,
                                           (min_args > 1 || min_args == 0) ? "s" : "");
        }

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

        return std::get<Function>(function_info);
    }
  • 通过keyword,调用map找到对应的commond处理对象,也就是如下内容
{1,     1,    {false,  do_start}}
  • 然后校验其参数个数是否合法
  • 最后返回std::get(function_info),实际上是如下内容
{false,  do_start}

这样就找到了每个commond对应实现的方法是哪个,最后解析出来数据会构建出一个commond对象,这个对象被保存到commands_变量中。

commands_.emplace_back(function->second, function->first, std::move(args), line);

除了commond关键字的解析外,commond命令可能还会有参数,这些参数就是通过如下代码保存到args中的。

case T_TEXT:
    args.emplace_back(state.text);
    break;

最后,当section全部解析完成后,会调用如下代码结束section的解析

case T_EOF:
    end_section();

    for (const auto& [section_name, section_parser] : section_parsers_) {
        section_parser->EndFile();
    }

    return;

end_section最后调用对应解析器的ActionParser类的EndSection

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

    return Success();
}

将action_添加到action_manager_的actions_集合对象中进行管理。

最后,所有rc文件中的Action都会按照如下数据结构方式进行管理:

ActionManager.png

Service解析

Service与Action解析根本的不同点就在于如下代码

if (section_parsers_.count(args[0])) {
    end_section();
    section_parser = section_parsers_[args[0]].get();
    section_start_line = state.line;
    if (auto result =
            section_parser->ParseSection(std::move(args), filename, state.line);
        !result) {
        parse_error_count_++;
        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
        section_parser = nullptr;
        bad_section_found = true;
    }
}

对于Action,section_parser为ActionParser;对于service,section_parser为ServiceParser;这也就导致后续调用的三个核心函数ParseSection、ParseLineSection、EndSection实现代码有所不同。

以如下service解析为例

service zygote /system/bin/app_process64 -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 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
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks
//system/core/init/service.cpp
    
Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,
                                            const std::string& filename, int line) {
    if (args.size() < 3) {
        return Error() << "services must have a name and a program";
    }

    const std::string& name = args[1];
    if (!IsValidName(name)) {
        return Error() << "invalid service name '" << name << "'";
    }

    filename_ = filename;

    ...

    std::vector<std::string> str_args(args.begin() + 2, args.end());


    service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);
    return Success();
}
  • 获取服务名name=“zygote”
  • 然后将后续参数放到str_args中(/system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server)
  • 最后使用name和str_args创建Service,并赋值给service_
//system/core/init/service.cpp
    
Result<Success> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {
    return service_ ? service_->ParseLine(std::move(args)) : Success();
}
    
Result<Success> Service::ParseLine(std::vector<std::string>&& args) {
    static const OptionParserMap parser_map;
    auto parser = parser_map.FindFunction(args);

    if (!parser) return parser.error();

    return std::invoke(*parser, this, std::move(args));
}

ParseLineSection最终是调用Service中的ParseLine:

  • OptionParserMap在前面有提到,它继承至KeywordMap
  • parser_map.FindFunction实际就是调用的KeywordMap.FindFunction
  • KeywordMap.FindFunction中会调用map()方法,这个方法被OptionParserMap所覆盖,实现如下:
const 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",
                        {0,     kMax, &Service::ParseCapabilities}},
        {"class",       {1,     kMax, &Service::ParseClass}},
        {"console",     {0,     1,    &Service::ParseConsole}},
        {"critical",    {0,     0,    &Service::ParseCritical}},
        {"disabled",    {0,     0,    &Service::ParseDisabled}},
        {"enter_namespace",
                        {2,     2,    &Service::ParseEnterNamespace}},
        {"file",        {2,     2,    &Service::ParseFile}},
        {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
        {"interface",   {2,     2,    &Service::ParseInterface}},
        {"ioprio",      {2,     2,    &Service::ParseIoprio}},
        {"keycodes",    {1,     kMax, &Service::ParseKeycodes}},
        {"memcg.limit_in_bytes",
                        {1,     1,    &Service::ParseMemcgLimitInBytes}},
        {"memcg.limit_percent",
                        {1,     1,    &Service::ParseMemcgLimitPercent}},
        {"memcg.limit_property",
                        {1,     1,    &Service::ParseMemcgLimitProperty}},
        {"memcg.soft_limit_in_bytes",
                        {1,     1,    &Service::ParseMemcgSoftLimitInBytes}},
        {"memcg.swappiness",
                        {1,     1,    &Service::ParseMemcgSwappiness}},
        {"namespace",   {1,     2,    &Service::ParseNamespace}},
        {"oneshot",     {0,     0,    &Service::ParseOneshot}},
        {"onrestart",   {1,     kMax, &Service::ParseOnrestart}},
        {"oom_score_adjust",
                        {1,     1,    &Service::ParseOomScoreAdjust}},
        {"override",    {0,     0,    &Service::ParseOverride}},
        {"priority",    {1,     1,    &Service::ParsePriority}},
        {"restart_period",
                        {1,     1,    &Service::ParseRestartPeriod}},
        {"rlimit",      {3,     3,    &Service::ParseProcessRlimit}},
        {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
        {"setenv",      {2,     2,    &Service::ParseSetenv}},
        {"shutdown",    {1,     1,    &Service::ParseShutdown}},
        {"sigstop",     {0,     0,    &Service::ParseSigstop}},
        {"socket",      {3,     6,    &Service::ParseSocket}},
        {"timeout_period",
                        {1,     1,    &Service::ParseTimeoutPeriod}},
        {"updatable",   {0,     0,    &Service::ParseUpdatable}},
        {"user",        {1,     1,    &Service::ParseUser}},
        {"writepid",    {1,     kMax, &Service::ParseWritepid}},
    };
    // clang-format on
    return option_parsers;
}

FindFunction实际返回的就是&Service::*,这里Service中所实现的方法主要是用来解析rc脚本中Service的Option选项,例如:

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 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
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
  • std::invoke(*parser, this, std::move(args))就是调用&Service::*方法,在这里方法中会将Option中解析的数据填充到前面创建的_service对象中
Result<Success> ServiceParser::EndSection() {
    if (service_) {
        Service* old_service = service_list_->FindService(service_->name());
        if (old_service) {
            if (!service_->is_override()) {
                return Error() << "ignored duplicate definition of service '" << service_->name()
                               << "'";
            }

            if (StartsWith(filename_, "/apex/") && !old_service->is_updatable()) {
                return Error() << "cannot update a non-updatable service '" << service_->name()
                               << "' with a config in APEX";
            }

            service_list_->RemoveService(*old_service);
            old_service = nullptr;
        }

        service_list_->AddService(std::move(service_));
    }

    return Success();
}

最后当一个Service section解析完后就被添加到service_list_中管理,整个过程构建的数据结构如下:

ServiceList.png

line_callback

line_callback这个不是一个重要的内容,在这里简单提一下即可,它并不是init进程在使用,而是ueventd进程使用的;在前面init进程执行流程中讲解了ueventd进程是如何启动的,启动入口ueventd_main如下

// system/core/init/main.cpp

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif

    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap function_map;

            return SubcontextMain(argc, argv, &function_map);
        }

        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    return FirstStageMain(argc, argv);
}

在ueventd_main会解析与ueventd相关的rc文件

int ueventd_main(int argc, char** argv) {
    ...

    auto ueventd_configuration = ParseConfig({"/ueventd.rc", "/vendor/ueventd.rc",
                                              "/odm/ueventd.rc", "/ueventd." + hardware + ".rc"});

    ...
    return 0;
}

在这里面会调用AddSingleLineParser添加一个行解析器,前面讲解init.rc都是调用AddSectionParser添加的段解析器

UeventdConfiguration ParseConfig(const std::vector<std::string>& configs) {
    Parser parser;
    UeventdConfiguration ueventd_configuration;

    parser.调用AddSectionParser添加的段解析器("subsystem",
                            std::make_unique<SubsystemParser>(&ueventd_configuration.subsystems));

    using namespace std::placeholders;
    parser.AddSingleLineParser(
            "/sys/",
            std::bind(ParsePermissionsLine, _1, &ueventd_configuration.sysfs_permissions, nullptr));
    parser.AddSingleLineParser("/dev/", std::bind(ParsePermissionsLine, _1, nullptr,
                                                  &ueventd_configuration.dev_permissions));
    parser.AddSingleLineParser("firmware_directories",
                               std::bind(ParseFirmwareDirectoriesLine, _1,
                                         &ueventd_configuration.firmware_directories));
    parser.AddSingleLineParser("modalias_handling",
                               std::bind(ParseModaliasHandlingLine, _1,
                                         &ueventd_configuration.enable_modalias_handling));
    parser.AddSingleLineParser("uevent_socket_rcvbuf_size",
                               std::bind(ParseUeventSocketRcvbufSizeLine, _1,
                                         &ueventd_configuration.uevent_socket_rcvbuf_size));

    for (const auto& config : configs) {
        parser.ParseConfig(config);
    }

    return ueventd_configuration;
}

AddSingleLineParser就是将解析器添加到了line_callbacks_中

void Parser::AddSingleLineParser(const std::string& prefix, LineCallback callback) {
    line_callbacks_.emplace_back(prefix, callback);
}

到这里,我们就明白了为什么前面分析init.rc解析时,直接忽略line_callbacks_了。

为什么需要这个行解析器呢,我们看一下ueventd.rc文件内容就明白了

firmware_directories /etc/firmware/ /odm/firmware/ /vendor/firmware/ /firmware/image/
uevent_socket_rcvbuf_size 16M

subsystem graphics
    devname uevent_devpath
    dirname /dev/graphics

subsystem drm
    devname uevent_devpath
    dirname /dev/dri

subsystem input
    devname uevent_devpath
    dirname /dev/input

subsystem sound
    devname uevent_devpath
    dirname /dev/snd

# ueventd can only set permissions on device nodes and their associated
# sysfs attributes, not on arbitrary paths.
#
# format for /dev rules: devname mode uid gid
# format for /sys rules: nodename attr mode uid gid
# shortcut: "mtd@NN" expands to "/dev/mtd/mtdNN"

/dev/null                 0666   root       root
/dev/zero                 0666   root       root
/dev/full                 0666   root       root
/dev/ptmx                 0666   root       root
/dev/tty                  0666   root       root
/dev/random               0666   root       root
/dev/urandom              0666   root       root
# Make HW RNG readable by group system to let EntropyMixer read it.
/dev/hw_random            0440   root       system
/dev/ashmem               0666   root       root
/dev/binder               0666   root       root
/dev/hwbinder             0666   root       root
/dev/vndbinder            0666   root       root

/dev/pmsg0                0222   root       log

# kms driver for drm based gpu
/dev/dri/*                0666   root       graphics

# these should not be world writable
/dev/uhid                 0660   uhid       uhid
/dev/uinput               0660   uhid       uhid
/dev/rtc0                 0640   system     system
/dev/tty0                 0660   root       system
/dev/graphics/*           0660   root       graphics
/dev/input/*              0660   root       input
/dev/v4l-touch*           0660   root       input
/dev/snd/*                0660   system     audio
/dev/bus/usb/*            0660   root       usb
/dev/mtp_usb              0660   root       mtp
/dev/usb_accessory        0660   root       usb
/dev/tun                  0660   system     vpn

# CDMA radio interface MUX
/dev/ppp                  0660   radio      vpn

# sysfs properties
/sys/devices/platform/trusty.*      trusty_version        0440  root   log
/sys/devices/virtual/input/input*   enable      0660  root   input
/sys/devices/virtual/input/input*   poll_delay  0660  root   input
/sys/devices/virtual/usb_composite/*   enable      0664  root   system
/sys/devices/system/cpu/cpu*   cpufreq/scaling_max_freq   0664  system system
/sys/devices/system/cpu/cpu*   cpufreq/scaling_min_freq   0664  system system

因为它里面有很多独立的行,所以定义了一个专门的解析器用于解析这些独立行。