文章大纲
- 引言
- 一、`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;
}
}
}
未完待续…