05_aosp12中init进程解析rc文件流程分析

一.概述

init进程启动后,会解析systemsystem_extvendorodmproduct分区下的*.rc文件,最后解析完成后,会得到一系列的Action和Service,并通过ActionManager存储所有的Action,通过ServiceList存储所有的Service,最后由SecondStageMain通过轮训调用ActionManager::ExecuteOneCommand触发执行。

二.rc文件解析流程
  • rc文件的解析是从init进程启动的第二阶段开始的,即SecondStageMain方法。

    源码位于system/core/init/init.cpp

    c++ 复制代码
    int SecondStageMain(int argc, char** argv) {
       ...
    
        const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
        Action::set_function_map(&function_map);
    
       ...
    
        ActionManager& am = ActionManager::GetInstance();
        ServiceList& sm = ServiceList::GetInstance();
    
        LoadBootScripts(am, sm);
    
       ...
    
        return 0;
    }
  • GetBuiltinFunctionMap

    源码位于system/core/init/builtins.cpp

    c++ 复制代码
    const BuiltinFunctionMap& GetBuiltinFunctionMap() {
        constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
        // clang-format off
        static const BuiltinFunctionMap builtin_functions = {
            ...
            {"class_start",             {1,     1,    {false,  do_class_start}}},
            ...
            {"trigger",                 {1,     1,    {false,  do_trigger}}},
            ...
        };
        // clang-format on
        return builtin_functions;
    }

    从源码可以看出,GetBuiltinFunctionMap的返回结果,里面记录了rc语法中的涉及的命令及执行该命令时要调用的函数。

  • 通过调用Action::set_function_map,GetBuiltinFunctionMap的返回会被保存到Action的静态成员属性中,

    源码位于system/core/init/action.h

    c++ 复制代码
    class Action {
      public:
        ...
        static void set_function_map(const BuiltinFunctionMap* function_map) {
            function_map_ = function_map;
        }
    
      private:
        ...
        static const BuiltinFunctionMap* function_map_;
    };
  • LoadBootScripts

    源码位于system/core/init/init.cpp

    c++ 复制代码
    static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
        Parser parser = CreateParser(action_manager, service_list);
    
        std::string bootscript = GetProperty("ro.boot.init_rc", "");
        
        // bootscript.empty(): 1
        if (bootscript.empty()) {
            parser.ParseConfig("/system/etc/init/hw/init.rc");
            // parser.ParseConfig("/system/etc/init"): 1
            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"): 1
            parser.ParseConfig("/system_ext/etc/init");
    
            // parser.ParseConfig("/vendor/etc/init"): 1 
            if (!parser.ParseConfig("/vendor/etc/init")) {
                late_import_paths.emplace_back("/vendor/etc/init");
            }
            // parser.ParseConfig("/odm/etc/init"): 0
            if (!parser.ParseConfig("/odm/etc/init")) {
                late_import_paths.emplace_back("/odm/etc/init");
            }
            // parser.ParseConfig("/product/etc/init"): 0
            if (!parser.ParseConfig("/product/etc/init")) {
                late_import_paths.emplace_back("/product/etc/init");
            }
        } else {
            parser.ParseConfig(bootscript);
        }
    }
  • CreateParser

    源码位于system/core/init/init.cpp

    c++ 复制代码
    Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
        Parser parser;
    		
      	// c++中std::make_unique相当于new对象,会返回一个std::unique_ptr,即智能指针,可以自动管理内存
      	// unique_ptr持有对对象的独有权,两个unique_ptr不能指向一个对象,不能进行复制操作只能进行移动操作
        parser.AddSectionParser("service",
                                std::make_unique<ServiceParser>(&service_list, GetSubcontext()));
        parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
        parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
    
        return parser;
    }

    依次调用Parser对象的AddSectionParser方法,并传入"service"和ServiceParser对象,"on"和ActionParser对象,"import"和ImportParser对象。

    AddSectionParser方法的源码位于system/core/init/parser.cpp

    c++ 复制代码
    void Parser::AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser) {
      	// std::move是移动操作,例如: p1 = std::move(p),指针p指向的对象会移动到p1。
      	// section_parsers_是一个std:map,相当于java中的HashMap
      	// section_parsers_中只有三个key,分别是on、service、import
        section_parsers_[name] = std::move(parser);
    }

    因此,CreateParser调用完成后,会创建一个map,并设置给Parser对象的私有成员属性section_parsers_持有,section_parsers_中只有三个key,service、on、import,分别对应ServiceParser、ActionParser、ImportParser对象。

    ServiceParser源码位于system/core/init/service_parser.cpp

    ActionParser源码位于system/core/init/action_parser.cpp

    ImportParser源码位于system/core/init/import_parser.cpp

    回到LoadBootScripts方法,继续调用ParseConfig,并依次传入/system/etc/init/hw/init.rc/system/etc/init/system_ext/etc/init/vendor/etc/init/odm/etc/init/product/etc/init

  • ParseConfig和ParseConfigDir

    源码位于system/core/init/parser.cpp

    c++ 复制代码
    bool Parser::ParseConfig(const std::string& path) {
        if (is_dir(path.c_str())) {
            return ParseConfigDir(path);
        }
        return ParseConfigFile(path);
    }
    
    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;
    }

    ParseConfig会判断传入路径是文件还是目录,如果是文件,调用ParseConfigFile,如果是目录,则遍历该目录下的*.rc文件,对文件调用ParseConfigFile。

  • ParseConfigFile

    源码位于system/core/init/parser.cpp

    c++ 复制代码
    bool Parser::ParseConfigFile(const std::string& path) {
        LOG(INFO) << "Parsing file " << path << "...";
        android::base::Timer t;
        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;
    }

    ParseConfigFile会读取rc文件的内容,并调用ParseData。

三.ParseData

源码位于system/core/init/parser.cpp

c++ 复制代码
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 = [&] {
        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 (;;) { 
        // 一行一行的解析rc文件内容
        switch (next_token(&state)) {
            case T_EOF:
                end_section();

                for (const auto& [section_name, section_parser] : section_parsers_) {
                    section_parser->EndFile();
                }
					// 6.最后rc文件解析完后,所有的Action会被存入
            		// ActionManager持有的 std::vector<std::unique_ptr<Action>> actions_
            		// 所有的Service会被存入
            		// ServiceList持有的 std::vector<std::unique_ptr<Service>> services_
            		// 最后退出循环
                return;
            case T_NEWLINE: {
              	// 2.	开始解析读取到的一行数据
              
                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.ok()) {
                        parse_error_count_++;
                        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                    }
                } else if (section_parsers_.count(args[0])) {
                  	// args[0]是当前行的第一个单词
                  	// C++中std:map的count函数是查找key,相当于Java中Map的contains
                  	
                  	// 3.解析以on、service或import开头的行
                  
                  	// 结束上一个section,
                  	// 如果上一个section以on开头,执行ActionParser的EndSection(),
                  	// 解析结果会被添加到ActionManager持有的 std::vector<std::unique_ptr<Action>> actions_ 中
                  	
                  	// 如果上一个section以service开头,执行ServiceParser的EndSection(),
                  	// 解析结果会被添加到ServiceList持有的 std::vector<std::unique_ptr<Service>> services_ 中
                  	
                  	// 如果上一个section以import开头,执行ImportParser的EndSection(),递归解析被import的rc文件
                    end_section();
                  
                  	// 如果args[0]等于on,section_parser为ActionParser
                  	// 执行section_parser->ParseSection会得到一个Action对象
                  	// Action对象的大致结构为:
                  	// Action {
                    //     std::string event_trigger_;					事件触发条件
                    //     std::vector<Command> commands_;			存储当前解析的Section中定义的所有命令
                    //     std::string filename_;								当前Section所属的rc文件路径
                    //     int line_;														当前Section的开头在rc文件中是第几行
                  	// 		 ...
                	// }
                  
                    // 如果args[0]等于service,section_parser为ServiceParser
                  	// 执行section_parser->ParseSection会得到一个Sevice对象
                  	// Sevice对象的大致结构为:
                  	// Sevice {
                  	// 		 const std::string name_;               解析到的service名称
                  	// 		 std::string filename_;									当前Section所属的rc文件路径
                  	// 		 const std::vector<std::string> args_;  service的可执行二进制文件路径及参数
                  	//		...
                		// }
                    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.ok()) {
                        parse_error_count_++;
                        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                        section_parser = nullptr;
                        bad_section_found = true;
                    }
                } else if (section_parser) { //如果当前行不是以on、service、import开头,说明是command或options
                  	// 4.解析当前section下面的command或options
                  	// command对应解析结果为Command对象,并存入当前Action对象持有的 std::vector<Command> commands_
                  	// options的解析结果会复制给当前Service对象的属性
                    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";
                }
              	// 5.当前行解析完成,清空args数组
                args.clear();
                break;
            }
            case T_TEXT:
            		// 1.将读取的一行数据按照空格拆分,并放到args中
                args.emplace_back(state.text);
                break;
        }
    }
}

ParseData会逐行解析rc文件的内容:

  • 如果解析到以import开头的一行,则通过ImportParser递归去解析被导入的rc文件

  • 以on开头的行到当前Section的最后一个command所在行的内容,认为是一个Action类型的Section,通过ActionParser解析为一个Action对象,并保存到ActionManager持有的 std::vector<std::unique_ptr<Action>> actions_。

  • 以service开头的行到当前Section的最后一个options所在行的内容,认为是一个Service类型的Section,通过ServiceParser解析为一个Service对象,并保存到ServiceList持有的 std::vector<std::unique_ptr> services_。

  • Action的关键信息

    c++ 复制代码
    Action {
        std::map<std::string, std::string> property_triggers_; 			 // 属性触发条件
         std::string event_trigger_;																// 事件触发条件
         std::vector<Command> commands_;										 // 存储当前解析的Section中定义的所有命令
         std::string filename_;																			// 当前Section所属的rc文件路径
         int line_;																									 // 当前Section的开头在rc文件中是第几行
         ...
    }
  • Service的关键信息

    c++ 复制代码
    Sevice {
        const std::string name_;									// 解析到的service名称
        std::string filename_;											// 当前Section所属的rc文件路径
        const std::vector<std::string> args_; 			// service的可执行二进制文件路径及参数
        ...																					// 其他option
    }
四.如何触发Action执行
  • 事件触发

    ActionManager::QueueEventTrigger(const std::string& trigger);

    c++ 复制代码
    void ActionManager::QueueEventTrigger(const std::string& trigger) {
        auto lock = std::lock_guard{event_queue_lock_};
        event_queue_.emplace(trigger);
    }
  • 系统属性改变触发

    ActionManager::QueuePropertyChange(const std::string& name, const std::string& value);

    c++ 复制代码
    void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) {
        auto lock = std::lock_guard{event_queue_lock_};
        event_queue_.emplace(std::make_pair(name, value));
    }
  • 内建Action触发

    ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name);

    c++ 复制代码
    void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
        auto lock = std::lock_guard{event_queue_lock_};
        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);
    
        event_queue_.emplace(action.get());
        actions_.emplace_back(std::move(action));
    }
  • 三种触发方式,都是把对应的触发条件添加到ActionManager持有的event_queue_队列中,真正触发执行是在SecondStageMain中完成的。

    SecondStageMain的最后会开启一个死循环,轮训调用ActionManager::ExecuteOneCommand

    system/core/init/init.cpp

    c++ 复制代码
    int SecondStageMain(int argc, char** argv) {
        ...
        
        ActionManager& am = ActionManager::GetInstance();
      
        ...
          
        while (true) {
            ...
    
            if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
                am.ExecuteOneCommand();
            }
    
            ...
        }
    
        return 0;
    }

    ActionManager::ExecuteOneCommand

    system/core/init/action_manager.cpp

    c++ 复制代码
    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()) {
                for (const auto& action : actions_) {
                    if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
                                   event_queue_.front())) {
                        current_executing_actions_.emplace(action.get());
                    }
                }
                event_queue_.pop();
            }
        }
    
        if (current_executing_actions_.empty()) {
            return;
        }
    
        auto action = current_executing_actions_.front();
    
        if (current_command_ == 0) {
            std::string trigger_name = action->BuildTriggersString();
            LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
                      << ":" << action->line() << ")";
        }
    
        action->ExecuteOneCommand(current_command_);
    
        // 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_;
        if (current_command_ == action->NumCommands()) {
            current_executing_actions_.pop();
            current_command_ = 0;
            if (action->oneshot()) {
                auto eraser = [&action](std::unique_ptr<Action>& a) { return a.get() == action; };
                actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser),
                               actions_.end());
            }
        }
    }

    ExecuteOneCommand会遍历之前从rc文件中解析到的所有action,从event_queue_中取出一个触发条件(如果有),触发条件可以是字符串、map、也可以是一个Action对象,通过这个触发条件过滤出满足条件的Action,同时将触发条件从event_queue_队列中移除。

    system/core/init/action.cpp

    c++ 复制代码
    bool Action::CheckPropertyTriggers(const std::string& name, const std::string& value) const {
        if (property_triggers_.empty()) {
            return true;
        }
    
        if (!name.empty()) {
            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;
    }
    
    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 {
        return this == builtin_action;
    }

    然后把满足条件的Action加入到current_executing_actions_队列,然后按顺序执行该Action中的一个command,同时会记录这个Action,当前已经执行的命令数。

    如果这个Action的所有command都被执行完了,则会从current_executing_actions_队列中移除,同时将当前已经执行的命令数清零,如果action的oneshot为true,action还会从ActionManager中移除。

    如果是从rc文件解析的Action,Action的oneshot属性为false。

    只有通过ActionManager::QueueBuiltinAction内建的Action,oneshot才会被设为true。

相关推荐
CyL_Cly1 小时前
Appteka下载 最新版18.4下载安装
android
张风捷特烈1 小时前
状态管理大乱斗#05 | Riverpod 源码评析 (中) - 上层建筑
android·前端·flutter
三少爷的鞋1 小时前
AsyncTask 已死多年:协程到底赢在哪里?
android
Gary Studio10 小时前
安卓HAL编写
android
_李小白12 小时前
【android opencv学习笔记】Day 2: Mat类(图片数据结构体)
android·opencv·学习
jinanwuhuaguo14 小时前
OpenClaw工程解剖——RAG、向量织构与“记忆宫殿”的索引拓扑学(第十三篇)
android·开发语言·人工智能·kotlin·拓扑学·openclaw
小怪吴吴16 小时前
idea 开发Android
android·java·intellij-idea
xiaoyan201517 小时前
2026爆肝!Flutter3.41纯手撸微信聊天APP原生应用
android·flutter·dart
jinanwuhuaguo18 小时前
OpenClaw协议霸权——从 MCP 标准到意图封建化的政治经济学(第十八篇)
android·人工智能·kotlin·拓扑学·openclaw