C/C++教程

Android 进阶——系统启动之Android init进程解析init.rc脚本(五)

本文主要是介绍Android 进阶——系统启动之Android init进程解析init.rc脚本(五),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章大纲

  • 引言
  • 一、`aosp/system/core/init.cpp#LoadBootScripts`函数加载init.rc 脚本
  • 二、创建Parser
  • 三、调用Parser:: ParseConfig
  • 四、 Parser::ParseData 开始解析

引言

前面介绍到Android init进程创建启动完毕后,但Android 特有的adbd、Zygote、Service Manager(C++)核心进程和服务都已经启动了,是通过什么方式启动的呢?前一篇文章总结道init.rc脚本的基本语法和结构并且知道是通过解析init.rc文件完成的,具体细节是怎么样的呢,接着往下看,系列文章链接如下:

  • Android 进阶——系统启动之BootLoader 简介及内核启动(一)
  • Android 进阶——系统启动之Linux init进程的创建和启动(二)
  • Android 进阶——系统启动之Android init进程的创建和启动(三)
  • Android 进阶——系统启动之Android init.rc脚本解析(四)
  • Android 进阶——系统启动之Android init进程解析init.rc脚本(五)

一、aosp/system/core/init.cpp#LoadBootScripts函数加载init.rc 脚本

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("/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);
    }
}

看来所有的解析工作都是封装到Parser 类中了。

二、创建Parser

aosp/system/core/init/parser.h

#ifndef _INIT_PARSER_H_
#define _INIT_PARSER_H_

#include <map>
#include <memory>
#include <string>
#include <vector>
#include "result.h"

//  SectionParser is an interface that can parse a given 'section' in init.
//
//  You can implement up to 4 functions below, with ParseSection being mandatory. The first two
//  functions return Result<Success> indicating if they have an error. It will be reported along
//  with the filename and line number of where the error occurred.
//
//  1) ParseSection
//    This function is called when a section is first encountered.
//
//  2) ParseLineSection
//    This function is called on each subsequent line until the next section is encountered.
//
//  3) EndSection
//    This function is called either when a new section is found or at the end of the file.
//    It indicates that parsing of the current section is complete and any relevant objects should
//    be committed.
//
//  4) EndFile
//    This function is called at the end of the file.
//    It indicates that the parsing has completed and any relevant objects should be committed.

namespace android {
namespace init {

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

class Parser {
  public:
    //  LineCallback is the type for callbacks that can parse a line starting with a given prefix.
    //
    //  They take the form of bool Callback(std::vector<std::string>&& args, std::string* err)
    //
    //  Similar to ParseSection() and ParseLineSection(), this function returns bool with false
    //  indicating a failure and has an std::string* err parameter into which an error string can
    //  be written.
    using LineCallback = std::function<Result<Success>(std::vector<std::string>&&)>;

    Parser();

    bool ParseConfig(const std::string& path);
    bool ParseConfig(const std::string& path, size_t* parse_errors);
    void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
    void AddSingleLineParser(const std::string& prefix, LineCallback callback);

  private:
    void ParseData(const std::string& filename, const std::string& data, size_t* parse_errors);
    bool ParseConfigFile(const std::string& path, size_t* parse_errors);
    bool ParseConfigDir(const std::string& path, size_t* parse_errors);

    std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
    std::vector<std::pair<std::string, LineCallback>> line_callbacks_;
};

}  // namespace init
}  // namespace android

#endif

aosp/system/core/init/parser.cpp

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;
}

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

三、调用Parser:: ParseConfig

bool Parser::ParseConfig(const std::string& path, size_t* parse_errors) {
    *parse_errors = 0;
    if (is_dir(path.c_str())) {
        return ParseConfigDir(path, parse_errors);
    }
    return ParseConfigFile(path, parse_errors);
}

ParseConfigFile中通过ReadFile把文件读入内存,存放到自动变量config_contents再传入ParseData函数

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

    config_contents->push_back('\n');  // TODO: fix parse_config.
    ParseData(path, *config_contents, parse_errors);
    for (const auto& [section_name, section_parser] : section_parsers_) {
        section_parser->EndFile();
    }

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

四、 Parser::ParseData 开始解析

void Parser::ParseData(const std::string& filename, const std::string& data, size_t* parse_errors) {
    // TODO: Use a parser with const input and remove this copy
    std::vector<char> data_copy(data.begin(), data.end());//定义一个向量(可变数组)临时存储文件的原始数据
    data_copy.push_back('\0');
	
    /*
    *core/init/tokenizer.h  parse_state结构体
    * 	struct parse_state
    	{
        char *ptr;
        char *text;
        int line;
        int nexttoken;
    	};
    *	
    */
    parse_state state;
    state.line = 0;
    state.ptr = &data_copy[0];//向量首地址初始化赋值给ptr
    state.nexttoken = 0;

    SectionParser* section_parser = nullptr;
    int section_start_line = -1;
    std::vector<std::string> args;
	//c++ 11 以上的lambda 语法 ,可以理解为一个匿名函数,end_section() 就是调用形式
    auto end_section = [&] {
        if (section_parser == nullptr) return;
        if (auto result = section_parser->EndSection(); !result) {
            (*parse_errors)++;
            LOG(ERROR) << filename << ": " << section_start_line << ": " << result.error();
        }
        section_parser = nullptr;
        section_start_line = -1;
    };

    for (;;) {
        switch (next_token(&state)) {
                //文件结束标志
            case T_EOF:
                end_section();
                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.
                for (const auto& [prefix, callback] : line_callbacks_) {
                    if (android::base::StartsWith(args[0], prefix)) {
                        end_section();

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

未完待续…

这篇关于Android 进阶——系统启动之Android init进程解析init.rc脚本(五)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!