Android 12 init(2) rc脚本解析和事件执行流程

文章托管在gitee上 Android Notes , 同步csdn
本文基于Android12 分析

在init启动的SecondStage,通过调用LoadBootScripts来解析启动脚本,也就是rc文件。下面来研究这个解析过程,之后再看看init如何处理事件并执行相关action的。

SecondStageMain

int SecondStageMain(int argc, char** argv) {
  ...
  const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
  Action::set_function_map(&function_map); // 设置 Action 需要的函数映射表
  ...
  InitializeSubcontext(); // 初始化Subcontext

  ActionManager& am = ActionManager::GetInstance(); // 创建action管理器
  ServiceList& sm = ServiceList::GetInstance(); // 创建服务管理列表

  LoadBootScripts(am, sm); // 加载并解析启动脚本
  ...
}

InitializeSubcontext

创建subcontext进程,用于执行init交给其的一些任务(比如后面执行的某些Command),通过socket与init进行通信

/// @system/core/init/subcontext.cpp
void InitializeSubcontext() {
    if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
        subcontext.reset( // 创建Subcontext, path_prefixes为"/vendor", "/odm"
                new Subcontext(std::vector<std::string>{"/vendor", "/odm"}, kVendorContext));
    }
}

/// @system/core/init/subcontext.h
Subcontext(std::vector<std::string> path_prefixes, std::string context, bool host = false)
    : path_prefixes_(std::move(path_prefixes)), context_(std::move(context)), pid_(0) {
    if (!host) { /// host默认为false
        Fork(); // 创建subcontext进程
    }
}

LoadBootScripts

加载并解析 init rc 脚本

/// @system/core/init/init.cpp
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    // 创建 Parser 对象
    Parser parser = CreateParser(action_manager, service_list);

    std::string bootscript = GetProperty("ro.boot.init_rc", "");//获取属性指定的rc
    if (bootscript.empty()) { // 没有指定rc,解析默认位置
        parser.ParseConfig("/system/etc/init/hw/init.rc"); // 首先解析 init.rc
        if (!parser.ParseConfig("/system/etc/init")) { // 解析 /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"); // 解析 /system_ext/etc/init 目录
        if (!parser.ParseConfig("/vendor/etc/init")) { // 解析 /vendor/etc/init 目录
            late_import_paths.emplace_back("/vendor/etc/init");
        }
        if (!parser.ParseConfig("/odm/etc/init")) { // 解析 /odm/etc/init 目录
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if (!parser.ParseConfig("/product/etc/init")) { // 解析 /product/etc/init 目录
            late_import_paths.emplace_back("/product/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}

CreateParser

/// @system/core/init/init.cpp
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser;
    // 添加各部分解析器
    // 创建ServiceParser 解析 service 服务,用于管理和启动native进程
    parser.AddSectionParser("service", std::make_unique<ServiceParser>(
                                               &service_list, GetSubcontext(), std::nullopt));
    // 创建ActionParser 解析 on action , 定义的一些动作                                           
    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
    // ImportParser解析import, 导入其他rc
    parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));

    return parser;
}

AddSectionParser按名称添加parser到集合

/// @system/core/init/parser.cpp
void Parser::AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser) {
    section_parsers_[name] = std::move(parser); // 按名称存储对应的parser
}
// 集合按名字存储对应的 SectionParser
std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;

接下来看解析流程,通过调用Parser::ParseConfig函数来实现解析指定路径的rc文件或目录下的rc文件。

Parser::ParseConfig

/// @system/core/init/parser.cpp
bool Parser::ParseConfig(const std::string& path) {
    if (is_dir(path.c_str())) { // 如果提供的目录
        return ParseConfigDir(path); // 解析配置目录
    }
    return ParseConfigFile(path);  // 解析配置文件
}

Parser::ParseConfigDir

执行解析配置目录操作,遍历目录调用ParseConfigFile解析每一个文件。忽略目录下的子目录,也就是不支持多层级目录。

/// @system/core/init/parser.cpp
bool Parser::ParseConfigDir(const std::string& path) {
    LOG(INFO) << "Parsing directory " << path << "...";
    std::unique_ptr<DIR, decltype(&closedir)> config_dir(opendir(path.c_str()), closedir);
    if (!config_dir) {
        PLOG(INFO) << "Could not import directory '" << path << "'";
        return false;
    }
    dirent* current_file;
    std::vector<std::string> files;
    while ((current_file = readdir(config_dir.get()))) { // 读取目录下的内容
        // Ignore directories and only process regular files.
        if (current_file->d_type == DT_REG) { // 如果是文件则添加到待解析集合
            std::string current_path =
                android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
            files.emplace_back(current_path);
        }
    }
    // Sort first so we load files in a consistent order (bug 31996208)
    std::sort(files.begin(), files.end());
    for (const auto& file : files) { // 遍历集合,解析文件
        if (!ParseConfigFile(file)) {
            LOG(ERROR) << "could not import file '" << file << "'";
        }
    }
    return true;
}

接下来看如何解析一个配置文件

Parser::ParseConfigFile

/// @system/core/init/parser.cpp
bool Parser::ParseConfigFile(const std::string& path) {
    LOG(INFO) << "Parsing file " << path << "...";
    android::base::Timer t;
    // 读取文件内容到string,实现在system/core/init/util.cpp,调用 android::base::ReadFdToString
    auto config_contents = ReadFile(path);
    if (!config_contents.ok()) {
        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;
}

Parser::ParseData

解析流程循环:

  • 获取的下一个token来决定接下来的动作,比如EOF结尾或者某个关键字
  • 遇到T_EOF则调用EndSection结束当前解析的ParseSection,退出循环
  • 遇到T_NEWLINE换新行,则进行解析一行
  • 如果获取的token是parser对应的关键字,比如on,则获取对应的parser进行解析,调用ParseSection
  • 如果token不是关键字,且上一步有获取parser,则进行解析一行,调用ParseLineSection
  • 遇到下一个关键字则调用EndSection结束当前解析的ParseSection,开启新的解析
  • 如果解析到文本,则添加到args集合
void Parser::ParseData(const std::string& filename, std::string* data) {
    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;

    auto end_section = [&] { // 结束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;
    };

    for (;;) {
        switch (next_token(&state)) { // 根据获取的下一个token来决定接下来的动作
            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()) { // 针对指定prefix的情况,比如 /dev/
                    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])) { // 如果第一个值能够匹配到parser, 比如是 service
                    end_section(); // 结束之前。
                    section_parser = section_parsers_[args[0]].get();
                    section_start_line = state.line;
                    if (auto result = // 解析 section
                                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;
                    }
                } else if (section_parser) { // 使用当前parser解析一行
                    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.clear();
                break;
            }
            case T_TEXT: // 是文本则添加到vector
                args.emplace_back(state.text);
                break;
        }
    }
}
next_token

该函数是用来解析token的,并获取有效的文本信息

/// @system/core/init/tokenizer.cpp
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;
}

接下来以解析on为例来分析,看关键字对应的是ActionParser

ActionParser::ParseSection

/// @system/core/init/action_parser.cpp
Result<void> ActionParser::ParseSection(std::vector<std::string>&& args,
                                        const std::string& filename, int line) {
    std::vector<std::string> triggers(args.begin() + 1, args.end()); // 除了on的其他参数
    if (triggers.size() < 1) { // on 后面需要指定trigger
        return Error() << "Actions must have a trigger";
    }

    Subcontext* action_subcontext = nullptr;
    // 检查路径是否匹配path_prefixes_中的路径前缀 /vendor, /odm
    if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
        action_subcontext = subcontext_; // 前缀匹配会获取到 subcontext_
    }

    std::string event_trigger;
    std::map<std::string, std::string> property_triggers;

    if (auto result = // 解析 trigger
                ParseTriggers(triggers, action_subcontext, &event_trigger, &property_triggers);
        !result.ok()) {
        return Error() << "ParseTriggers() failed: " << result.error();
    }
    // 创建该action对象,第一个参数false表示非oneshot,
    auto action = std::make_unique<Action>(false, action_subcontext, filename, line, event_trigger,
                                           property_triggers);

    action_ = std::move(action); // 缓存此解析的action,后续解析line的时候会用到
    return {};
}

ParseTriggers

以解析 on post-fs-data && property:ro.debuggable=1 为例分析,args 就是on 之后的内容。

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 (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 { // 否则是事件触发器,比如 post-fs-data
            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 {};
}

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:"); // property:ro.debuggable=1
    std::string prop_name(trigger.substr(prop_str.length()));// 去除前缀 ro.debuggable=1
    size_t equal_pos = prop_name.find('=');// 找到 =
    if (equal_pos == std::string::npos) {
        return Error() << "property trigger found without matching '='";
    }

    std::string prop_value(prop_name.substr(equal_pos + 1));// = 后面的是值
    prop_name.erase(equal_pos); // 等号前面的是属性名

    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,并获取了事件触发器和属性触发器。接下来解析它的Command命令列表

ParseLineSection

/// @system/core/init/action_parser.cpp
Result<void> ActionParser::ParseLineSection(std::vector<std::string>&& args, int line) {
    return action_ ? action_->AddCommand(std::move(args), line) : Result<void>{};// 通过Action解析Command
}

Action::AddCommand

/// @system/core/init/action.cpp
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();
    }
    // 找到匹配的函数,将新创建的 Command 添加到commands_列表
    commands_.emplace_back(map_result->function, map_result->run_in_subcontext, std::move(args),
                           line);
    return {};
}

创建 Command

Command::Command(BuiltinFunction f, bool execute_in_subcontext, std::vector<std::string>&& args,
                 int line)
    : func_(std::move(f)), // 函数
      execute_in_subcontext_(execute_in_subcontext), // 是否在subcontext中执行
      args_(std::move(args)), // 参数
      line_(line) /* 命令在文件行号*/ {}

function_map_ 实际上是KeywordMap的实例,看看它的实现。

KeywordMap::Find
Result<Value> Find(const std::vector<std::string>& args) const {
    if (args.empty()) return Error() << "Keyword needed, but not provided";
    // 以 copy /proc/cmdline /dev/urandom 为例
    auto& keyword = args[0]; // 取出关键字 copy
    auto num_args = args.size() - 1; // 关键字copy 后的其他参数

    auto result_it = map_.find(keyword); // 找到copy对应的 MapValue
    if (result_it == map_.end()) {
        return Errorf("Invalid keyword '{}'", keyword);
    }

    auto result = result_it->second; // MapValue

    auto min_args = result.min_args;
    auto max_args = result.max_args;
    if (min_args == max_args && num_args != min_args) {// 检查参数的数量
        return Errorf("{} requires {} argument{}", keyword, 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 Errorf("{} requires at least {} argument{}", keyword, min_args,
                          min_args > 1 ? "s" : "");
        } else {
            return Errorf("{} requires between {} and {} arguments", keyword, min_args,
                          max_args);
        }
    }

    return result.value;
}

看一下KeywordMap的实现

// Value is the return value of Find(), which is typically either a single function or a struct with
// additional information.
template <typename Value>
class KeywordMap {
  public:
    struct MapValue {
        size_t min_args;
        size_t max_args;
        Value value;
    };

    KeywordMap() {}
    KeywordMap(std::initializer_list<std::pair<const std::string, MapValue>> init) : map_(init) {}
    Result<Value> Find(const std::vector<std::string>& args) const { ... }

  private:
    std::map<std::string, MapValue> map_; // 函数名+MapValue组合
};
BuiltinFunctionMap

function_map_ 是一些内置函数映射表,通过GetBuiltinFunctionMap(),然后通过Action::set_function_map设置进来的。BuiltinFunctionMap 是KeywordMap的别名。

/// @system/core/init/builtins.h
using BuiltinFunction = std::function<Result<void>(const BuiltinArguments&)>;

struct BuiltinFunctionMapValue {
    bool run_in_subcontext;
    BuiltinFunction function;
};

using BuiltinFunctionMap = KeywordMap<BuiltinFunctionMapValue>;

/// 内置函数映射表,当Command执行 copy 时, 会调用 do_copy 函数
/// @system/core/init/builtins.cpp
// 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 =
        // 函数名, MapValue{ min_args,max_args,BuiltinFunctionMapValue{ run_in_subcontext, BuiltinFunction } }
        {"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;
}
// Builtin-function-map end

当解析完一个action,会执行EndSection函数

ActionParser::EndSection

Result<void> ActionParser::EndSection() {
    if (action_ && action_->NumCommands() > 0) {
        action_manager_->AddAction(std::move(action_)); // 将当前解析的action添加到集合
    }

    return {};
}

动作、内置动作和事件触发器

  • 动作(Action)
    通常是在rc中使用 on 声明的动作,action通常需要一些事件来触发
  • 内置动作(Builtin Action)
    只在代码里面调用QueueBuiltinAction的action,其他action在rc里使用 on 声明。
  • 事件触发器(Trigger)
    调用QueueEventTrigger插入事件触发器。这种触发器通常用一个字符串表示,会有一些action与之对应。

看下 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), // action所在文件和行号
      line_(line) {}

action通常在事件发生时触发,事件都存放在event_queue_集合里

std::vector<std::unique_ptr<Action>> actions_; // action集合
std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_
        GUARDED_BY(event_queue_lock_); // 事件队列
mutable std::mutex event_queue_lock_;
std::queue<const Action*> current_executing_actions_; // 正在出现的action队列
std::size_t current_command_; // 已执行的命令数量

ActionManager::QueueBuiltinAction

void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
    auto lock = std::lock_guard{event_queue_lock_};
		// 创建action,注意第一个参数为true 表示一次性的 oneshot
    auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
                                           std::map<std::string, std::string>{});
    action->AddCommand(std::move(func), {name}, 0);// fun 添加到命令列表,执行action的命令时会被调用

    event_queue_.emplace(action.get());  // 添加到事件队列
    actions_.emplace_back(std::move(action)); // 添加到action队列
}

ActionManager::QueueEventTrigger

void ActionManager::QueueEventTrigger(const std::string& trigger) {
    auto lock = std::lock_guard{event_queue_lock_};
    event_queue_.emplace(trigger); // 添加到事件队列
}

QueueBuiltinAction和QueueEventTrigger只是将相关action和事件添加进队列,实际上没有真正去执行,而实际去执行是在其主循环里面触发的,通过 ActionManager#ExecuteOneCommand

ActionManager::ExecuteOneCommand

/// @system/core/init/action_manager.cpp
void ActionManager::ExecuteOneCommand() {
    {
        auto lock = std::lock_guard{event_queue_lock_};
        // Loop through the event queue until we have an action to execute
        while (current_executing_actions_.empty() && !event_queue_.empty()) { // 当前没有执行的action,但是有事件
            for (const auto& action : actions_) { // 找到此事件对应要处理的action,可能对应多个
                if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
                               event_queue_.front())) {
                    current_executing_actions_.emplace(action.get()); // 一个事件可以对应多个 action
                }
            }
            event_queue_.pop();
        }
    }

    if (current_executing_actions_.empty()) {
        return;
    }
    // 返回 queue 中第一个元素的引用,而不是删除
    auto action = current_executing_actions_.front();

    if (current_command_ == 0) { // 处理此action的第一条命令时打印
        std::string trigger_name = action->BuildTriggersString();
        LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
                  << ":" << action->line() << ")";
    }

    action->ExecuteOneCommand(current_command_); // 回调每个action匹配的命令

    // If this was the last command in the current action, then remove
    // the action from the executing list.
    // If this action was oneshot, then also remove it from actions_.
    ++current_command_;  // 每执行一次数量加1
    if (current_command_ == action->NumCommands()) { // 如果此 action的命令全部执行完毕
        current_executing_actions_.pop(); // 从正执行列表删除
        current_command_ = 0;
        if (action->oneshot()) { // 如果是一次性的 还有从action列表移除。 通常Builtin Action是一次性的
            auto eraser = [&action](std::unique_ptr<Action>& a) { return a.get() == action; };
            actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser),
                           actions_.end());
        }
    }
}

Action::CheckEvent

检查event 与 action 是否匹配

bool Action::CheckEvent(const EventTrigger& event_trigger) const { // 检查事件触发器
    return event_trigger == event_trigger_ && CheckPropertyTriggers();//触发器满足并且所有实现也匹配
}

bool Action::CheckEvent(const PropertyChange& property_change) const { // 检查属性变化事件
    const auto& [name, value] = property_change;
    return event_trigger_.empty() && CheckPropertyTriggers(name, value);
}

bool Action::CheckEvent(const BuiltinAction& builtin_action) const { // 检查内置action,其event和action是同一个对象
    return this == builtin_action;
}


// This function checks that all property triggers are satisfied, that is
// for each (name, value) in property_triggers_, check that the current
// value of the property 'name' == value.
//
// It takes an optional (name, value) pair, which if provided must
// be present in property_triggers_; it skips the check of the current
// property value for this pair.
bool Action::CheckPropertyTriggers(const std::string& name, const std::string& value) const {// 检查所有属性是否匹配
    if (property_triggers_.empty()) { // 需要包含属性trigger -> property:aa.bb.cc=xxx
        return true;
    }

    if (!name.empty()) { // 如果指定key,需要检查value是否满足指定触发值
        auto it = property_triggers_.find(name);
        if (it == property_triggers_.end()) {
            return false;
        }
        const auto& trigger_value = it->second;
        if (trigger_value != "*" && trigger_value != value) {
            return false;
        }
    }
    // 指定值满足 或 指定值为空。 判断所有非指定的属性键值要满足触发值
    for (const auto& [trigger_name, trigger_value] : property_triggers_) {
        if (trigger_name != name) { // 判断除了指定触发键之外的
            std::string prop_value = android::base::GetProperty(trigger_name, "");
            if (trigger_value == "*" && !prop_value.empty()) {
                continue;
            }
            if (trigger_value != prop_value) return false;
        }
    }
    return true;
}

Action::ExecuteOneCommand

执行一条Command

/// @system/core/init/action.cpp
void Action::ExecuteOneCommand(std::size_t command) const {
    // We need a copy here since some Command execution may result in
    // changing commands_ vector by importing .rc files through parser
    Command cmd = commands_[command];
    ExecuteCommand(cmd);
}

// 执行某一条命令
void Action::ExecuteCommand(const Command& command) const {
    android::base::Timer t;
    auto result = command.InvokeFunc(subcontext_); // 调用执行对应的命令
    auto duration = t.duration();

    // Any action longer than 50ms will be warned to user as slow operation
    if (!result.has_value() || duration > 50ms ||
        android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
        std::string trigger_name = BuildTriggersString();
        std::string cmd_str = command.BuildCommandString();

        LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
                  << ":" << command.line() << ") took " << duration.count() << "ms and "
                  << (result.ok() ? "succeeded" : "failed: " + result.error().message());
    }
}

Command::InvokeFunc

/// @system/core/init/action.cpp
Result<void> Command::InvokeFunc(Subcontext* subcontext) const {
    if (subcontext) { // 指定了subcontext
        if (execute_in_subcontext_) { // 如果指定在 subcontext 下执行
            return subcontext->Execute(args_);
        }

        auto expanded_args = subcontext->ExpandArgs(args_);
        if (!expanded_args.ok()) { // 膨胀处理失败,则结束处理
            return expanded_args.error();
        }
        return RunBuiltinFunction(func_, *expanded_args, subcontext->context());
    }

    return RunBuiltinFunction(func_, args_, kInitContext);
}
  • 当指定了不为空的subcontext,
  • 若execute_in_subcontext_为true,则会直接调用subcontext->Execute
  • 否则会先subcontext->ExpandArgs通过subcontext进程对args进行膨胀处理(主要是将 ${prop_name} 解析成对应的属性值),然后在调用RunBuiltinFunction
  • 未指定subcontext则直接调用RunBuiltinFunction

RunBuiltinFunction

执行内置的函数

Result<void> RunBuiltinFunction(const BuiltinFunction& function,
                                const std::vector<std::string>& args, const std::string& context) {
    auto builtin_arguments = BuiltinArguments(context);

    builtin_arguments.args.resize(args.size());
    builtin_arguments.args[0] = args[0];
    for (std::size_t i = 1; i < args.size(); ++i) {
       // ExpandProps函数将属性 ${prop_name} 解析成对应的属性值,在system/core/init/util.cpp 实现
        auto expanded_arg = ExpandProps(args[i]);
        if (!expanded_arg.ok()) {
            return expanded_arg.error();
        }
        builtin_arguments.args[i] = std::move(*expanded_arg);
    }

    return function(builtin_arguments); // 调用对应的函数
}

比如对于如下Command,则会调用do_setprop去将vendor.qemu.timezone的属性值设置给persist.sys.timezone。

setprop persist.sys.timezone ${vendor.qemu.timezone}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值