「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。
系统启动流程分析之解析工具分析
在安卓11.0系统启动源码中,此前我们有分析过,在系统启动中,调用SecondStageMain函数来启动zygote以及系统服务,而在这个过程中,有一个很重要的环节就是,解析配置文件,而要解析配置文件,首先得要建立解析工具。
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
// 1. 创建对应的解析工具
Parser parser = CreateParser(action_manager, service_list);
// 2. 获取对应的解析文件
std::string bootscript = GetProperty("ro.boot.init_rc", "");
// 若ro.boot.init_rc指向对应的解析文件未定义,则直接解析指定的解析文件
if (bootscript.empty()) {
parser.ParseConfig("/system/etc/init/hw/init.rc");
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");
if (!parser.ParseConfig("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
if (!parser.ParseConfig("/product/etc/init")) {
late_import_paths.emplace_back("/product/etc/init");
}
} else {
// 若ro.boot.init_rc属性已定义,则直接解析其指向的配置文件
parser.ParseConfig(bootscript);
}
}
从代码中看,系统源码中使用LoadBootScripts函数来解析配置文件,而在这边,会通过CreateParser函数,来创建三个不同类别的解析工具,接下来,我们就来分析下,这三个配置解析工具是如何解析对应的配置文件的。
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
Parser parser;
parser.AddSectionParser("service", std::make_unique<ServiceParser>(
&service_list, GetSubcontext(), std::nullopt));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
return parser;
}
CreateParser函数,有两个参数,ActionManager对象和ServiceList对象,这两个对象的初始化在前文中,我们不做分析,主要是初始化工作。该函数返回一个Parser对象(解析器),这个我们稍后遇到后再行分析。
首先,通过Parser对象的AddSectionParser函数,往Parser对象中添加了三个对应的解析工具。
std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
void Parser::AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser) {
section_parsers_[name] = std::move(parser);
}
可以看到,在Parser对象中定义了名称为section_parsers_的map,然后将三个解析工具添加到该map中,可以看到,对应的key分别为”service”、”on”和“import”,而对应的,其value对应的对象,均继承于SectionParser类,而SectionParser的定义很简单。
system/core/init/parser.h
class SectionParser {
public:
virtual ~SectionParser() {}
virtual Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) = 0;
virtual Result<void> ParseLineSection(std::vector<std::string>&&, int) { return {}; };
virtual Result<void> EndSection() { return {}; };
virtual void EndFile(){};
};
接下来,我们一一分析一下三个解析工具
解析器的入口:Parser解析器
初始化
Parser::Parser() {}
开始解析
解析的过程,从上述的LoadBootScripts函数中,可致,通过调用Parser的ParseConfig函数来启动解析,那么此处,我们开始,
parser.ParseConfig(bootscript);
此处,由于我们需要解析的是/system/core/rootdir/init.zygote32.rc文件,所以此处的bootscript为/system/core/rootdir/init.zygote32.rc字符串
bool Parser::ParseConfig(const std::string& path) {
if (is_dir(path.c_str())) {
return ParseConfigDir(path);
}
return ParseConfigFile(path);
}
判断当前传入路径是否是文件夹,若为文件夹,则调用ParseConfigDir来解析该文件夹下的每一个配置文件,而此处我们传入的是一个文件,因此ParseConfigFile函数
bool Parser::ParseConfigFile(const std::string& path) {
LOG(INFO) << "Parsing file " << path << "...";
android::base::Timer t;
// 1. 从文件中读取对应的配置文件中的所有内容,保存为字符串形式
auto config_contents = ReadFile(path);
if (!config_contents.ok()) {
LOG(INFO) << "Unable to read config file '" << path << "': " << config_contents.error();
return false;
}
// 2. 调用ParseData函数,解析上述配置文件中的所有配置内容
ParseData(path, &config_contents.value());
LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
return true;
}
从上述代码可知,此处有两个步骤
从文件中读取对应的配置文件中的所有内容,保存为字符串形式,这部分,在此处不再分析
其次,调用ParseData函数,来解析对应的配置文件内容
void Parser::ParseData(const std::string& filename, std::string* data) {
// 1. 给解析数据的末尾添加结束符
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;
// 2. 定义一个end_section函数
// 函数的主要作用是,当配置文件数据解析完成后,做一些关闭操作
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;
};
3. 无限循环,解析配置数据
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.
// 从字符串中查找以args[0]开头的对应的子字符串
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
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])) {
end_section();
// 获取解析工具
section_parser = section_parsers_[args[0]].get();
section_start_line = state.line;
// 解析Section
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;
}
// 如果在库中查找到对应的Section Parser工具
} else if (section_parser) {
// 调用解析工具的ParseLineSection来解析对应的一行
if (auto result = section_parser->ParseLineSection(std::move(args), state.line);
!result.ok()) {
parse_error_count_++;
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
}
// else
} else if (!bad_section_found) {
parse_error_count_++;
LOG(ERROR) << filename << ": " << state.line
<< ": Invalid section keyword found";
}
args.clear();
break;
}
// 如果是TEXT文本,则直接添加其为参数
case T_TEXT:
args.emplace_back(state.text);
break;
}
}
}
如上述代码可知,此处
首先,给对应的配置数据添加结束符,以防访问到内存中其他的数据
其次,将配置文件数据使用parse_state结构体来操作
struct parse_state
{
char *ptr; // 此处的state的ptr指向配置文件数据的首字符
char *text; // 默认数据
int line; // 默认为0
int nexttoken; // 默认为0
};
再次,定义一个end_section函数引用,这个函数的主要作用是,若section_parser不为空,则调用其EndSection函数,做一些结束解析工作。
最后,通过一个循环,来一点点地解析配置文件数据
接下来,我们来开始解析对应的配置文件数据
循环中,是一个switch语句,switch的主体是next_token函数,参数为上述定义的parse_state对象引用
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;
}
可以看到,这个next_token函数,主要工作如下
若当前state->ptr指向的字符为大写字母或者小写字母,则保存此字符为继续指向下一个字符,并解析,直至解析出一个非字母的字符,最终将上述全部解析的字母使用state->text指向其首部,然后返回T_TEXT
若当前为换行符’\n’,则表明此时上一行已经解析完成,将state->ptr指向当前的后一个位置,并且返回T_NEWLINE
若当前为空格符、’\t’、’\r’等,则继续解析下一个字符
若当前字符为’#’,则过滤该行数据,当然,若最终解析的最后一个字符为’\n’,则返回T_NEWLINE,若不是,则表明配置文件数据已经解析完成,则直接返回T_EOF
那么,再回到ParseData的for循环中
当next_token函数返回的为T_EOF,表明配置文件已经解析完成,此处会调用所有的解析工具(此处为上述通过AddSectionParser添加的三个工具)的EndSection来结束解析
当next_token函数返回的是T_NEWLINE,则获取对应的args中的所有数据进行响应的操作,那么args中的数据从哪儿来的呢?看下面的解析
当next_token函数返回的是T_TEXT,则将返回回来的对应字符串添加到args字符串数组中
因此,综合上述ParseData的解析过程,可知,此处是按行解析,若解析到字符串的时候,则将其添加到args字符串数组中,然后当该行解析完成时,则交由T_NEWLINE对应的操作来解析,若配置数据解析完成后,则交由T_EOF对应的操作来处理
接下来,我们就来看下,如下的三个解析工具具体的解析工作。
ServiceParser解析工具
初始化
从上述代码看,ServiceParser的初始化语句如下
std::make_unique<ServiceParser>(&service_list, GetSubcontext(), std::nullopt)
而ServiceParser的构造函数如下
ServiceParser(ServiceList* service_list, Subcontext* subcontext,
const std::optional<InterfaceInheritanceHierarchyMap>& interface_inheritance_hierarchy,
bool from_apex = false)
: service_list_(service_list),
subcontext_(subcontext),
interface_inheritance_hierarchy_(interface_inheritance_hierarchy),
service_(nullptr),
from_apex_(from_apex) {}
也即,此处将ServiceParser对象的
名称为service_list_的ServiceList对象引用指向刚刚创建的ServiceList对象,
名称为subcontext_的Subcontext对象引用指向前文的Subcontext对象,
名称为interface_inheritance_hierarchy_为nullopt,
名称为service_的Service对象指向nullptr
from_apex_设定为false
解析流程
在ServiceParser解析器解析的过程中,肯定需要一个配置文件进行配合,那么我们就使用经典的zygote配置文件来解析一遍吧,此处我们使用init.zygote32.rc配置文件
service zygote /system/bin/app_process -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 exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
task_profiles ProcessCapacityHigh
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
通过Parser的ParseData函数分析可知,配置文件的解析是按行解析,因此此处,首先会读取第一行的所有内容,然后遇到字符串,则将其添加到args中,然后一行解析完成后,则在T_NEWLINE中处理,因此,我们一行行地分析
第一行
首先来看第一行
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
经过上述的分析,此处最开始由于是有字母(包含’/’字符、’-’)组成,因此会将所有的字符串加入到args字符串数组中
也就是在遇到最后的’\n’时,args中的数据如下
{
“service”,
“zygote”,
“/system/bin/app_process”,
“-Xzygote”,
“/system/bin”,
“--zygote”,
“—start-system-server”
}
接下来是换行符,即返回T_NEWLINE
case T_NEWLINE: {
// 确认解析行数
state.line++;
// 如果args为空,则无需解析
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.
// 从字符串中查找以args[0]开头的对应的子字符串
// 此处由于line_callbacks为定义,因此此处无法查出对应的line_callback
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()) {
// 关闭section解析工具
end_section();
if (auto result = line_callback->second(std::move(args)); !result.ok()) {
parse_error_count_++;
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
}
// 通过args[0]字符串来判断对应的map中是否有args[0]对应的解析工具
} else if (section_parsers_.count(args[0])) {
end_section();
// 获取解析工具
section_parser = section_parsers_[args[0]].get();
section_start_line = state.line;
// 解析Section
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;
}
// 如果当前的args[0]没有找到对应的解析工具,则判断解析工具是否已经存在
} else if (section_parser) {
// 调用解析工具的ParseLineSection来解析对应的一行
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清空,以便下一行解析
args.clear();
break;
}
如果上述代码,由于args[0]为”service”字符串,因此在section_parser_的map中找到其对应的是ServiceParser解析工具,因此section_parser设定为ServiceParser工具,此后调用该工具的ParseSection函数
Result<void> ServiceParser::ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) {
// 此处args的个数为7个,不满足条件
if (args.size() < 3) {
return Error() << "services must have a name and a program";
}
// 获取对应的name为”zygote”
const std::string& name = args[1];
// 判断名称是否合法
if (!IsValidName(name)) {
return Error() << "invalid service name '" << name << "'";
}
// 文件路径设定
filename_ = filename;
Subcontext* restart_action_subcontext = nullptr;
// 判断是否是/vendor下的或者/odm下的配置文件解析,此处不是
if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
restart_action_subcontext = subcontext_;
}
// 获取args的后五个参数
std::vector<std::string> str_args(args.begin() + 2, args.end());
......
// 初始化一个名称为service_的Service对象
service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args, from_apex_);
return {};
}
从上述的代码可以看到,这段代码主要是创建了一个Service对象,并且初始化service_指向该对象引用
Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
const std::vector<std::string>& args, bool from_apex)
: Service(name, 0, 0, 0, {}, 0, "", subcontext_for_restart_commands, args, from_apex) {}
Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
const std::vector<gid_t>& supp_gids, int namespace_flags,
const std::string& seclabel, Subcontext* subcontext_for_restart_commands,
const std::vector<std::string>& args, bool from_apex)
: name_(name),
classnames_({"default"}),
flags_(flags),
pid_(0),
crash_count_(0),
proc_attr_{.ioprio_class = IoSchedClass_NONE,
.ioprio_pri = 0,
.uid = uid,
.gid = gid,
.supp_gids = supp_gids,
.priority = 0},
namespaces_{.flags = namespace_flags},
seclabel_(seclabel),
subcontext_(subcontext_for_restart_commands),
onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0,
"onrestart", {}),
oom_score_adjust_(DEFAULT_OOM_SCORE_ADJUST),
start_order_(0),
args_(args),
from_apex_(from_apex) {}
根据其构造函数,此处主要设置其name_为zygote,args_为上述读取的最后五个参数数组,即
{
“/system/bin/app_process”,
“-Xzygote”,
“/system/bin”,
“--zygote”,
“—start-system-server”
}
第二行
接下来解析第二行
class main
由上述分析可知,此处会解析出args包含两个字符串参数,即”class”和”main”
然后进入T_NEWLINE,此时由于class无对应的解析工具,且section_parser已经设定为ServiceParser,因此调用ServiceParser的ParseLineSection函数
Result<void> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {
// 前一行解析的时候已经创建
if (!service_) {
return {};
}
// 从GetParserMap中获取解析工具(对应解析方法)
auto parser = GetParserMap().Find(args);
if (!parser.ok()) return parser.error();
// 获取到对应的解析方法后,调用它
return std::invoke(*parser, this, std::move(args));
}
从上述代码分析,获取对应的解析方法再调用它
const KeywordMap<ServiceParser::OptionParser>& ServiceParser::GetParserMap() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
// clang-format off
static const KeywordMap<ServiceParser::OptionParser> parser_map = {
{"capabilities", {0, kMax, &ServiceParser::ParseCapabilities}},
{"class", {1, kMax, &ServiceParser::ParseClass}},
{"console", {0, 1, &ServiceParser::ParseConsole}},
{"critical", {0, 2, &ServiceParser::ParseCritical}},
{"disabled", {0, 0, &ServiceParser::ParseDisabled}},
{"enter_namespace", {2, 2, &ServiceParser::ParseEnterNamespace}},
{"file", {2, 2, &ServiceParser::ParseFile}},
{"group", {1, NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}},
{"interface", {2, 2, &ServiceParser::ParseInterface}},
{"ioprio", {2, 2, &ServiceParser::ParseIoprio}},
{"keycodes", {1, kMax, &ServiceParser::ParseKeycodes}},
{"memcg.limit_in_bytes", {1, 1, &ServiceParser::ParseMemcgLimitInBytes}},
{"memcg.limit_percent", {1, 1, &ServiceParser::ParseMemcgLimitPercent}},
{"memcg.limit_property", {1, 1, &ServiceParser::ParseMemcgLimitProperty}},
{"memcg.soft_limit_in_bytes",
{1, 1, &ServiceParser::ParseMemcgSoftLimitInBytes}},
{"memcg.swappiness", {1, 1, &ServiceParser::ParseMemcgSwappiness}},
{"namespace", {1, 2, &ServiceParser::ParseNamespace}},
{"oneshot", {0, 0, &ServiceParser::ParseOneshot}},
{"onrestart", {1, kMax, &ServiceParser::ParseOnrestart}},
{"oom_score_adjust", {1, 1, &ServiceParser::ParseOomScoreAdjust}},
{"override", {0, 0, &ServiceParser::ParseOverride}},
{"priority", {1, 1, &ServiceParser::ParsePriority}},
{"reboot_on_failure", {1, 1, &ServiceParser::ParseRebootOnFailure}},
{"restart_period", {1, 1, &ServiceParser::ParseRestartPeriod}},
{"rlimit", {3, 3, &ServiceParser::ParseProcessRlimit}},
{"seclabel", {1, 1, &ServiceParser::ParseSeclabel}},
{"setenv", {2, 2, &ServiceParser::ParseSetenv}},
{"shutdown", {1, 1, &ServiceParser::ParseShutdown}},
{"sigstop", {0, 0, &ServiceParser::ParseSigstop}},
{"socket", {3, 6, &ServiceParser::ParseSocket}},
{"stdio_to_kmsg", {0, 0, &ServiceParser::ParseStdioToKmsg}},
{"task_profiles", {1, kMax, &ServiceParser::ParseTaskProfiles}},
{"timeout_period", {1, 1, &ServiceParser::ParseTimeoutPeriod}},
{"updatable", {0, 0, &ServiceParser::ParseUpdatable}},
{"user", {1, 1, &ServiceParser::ParseUser}},
{"writepid", {1, kMax, &ServiceParser::ParseWritepid}},
};
// clang-format on
return parser_map;
}
可以看到,class字符串对应的解析函数为ServiceParser::ParseClass
Result<void> ServiceParser::ParseClass(std::vector<std::string>&& args) {
service_->classnames_ = std::set<std::string>(args.begin() + 1, args.end());
return {};
}
此处设置service_对应引用的classnames_字段为args的第二个参数,即main
第三行
接下来,第三行
priority -20
根据上述分析,此处调用ServiceParser::ParsePriority函数引用
Result<void> ServiceParser::ParsePriority(std::vector<std::string>&& args) {
service_->proc_attr_.priority = 0;
if (!ParseInt(args[1], &service_->proc_attr_.priority,
static_cast<int>(ANDROID_PRIORITY_HIGHEST), // highest is negative
static_cast<int>(ANDROID_PRIORITY_LOWEST))) {
return Errorf("process priority value must be range {} - {}", ANDROID_PRIORITY_HIGHEST,
ANDROID_PRIORITY_LOWEST);
}
return {};
}
可知,设定service_->proc_attr_.priority为-20,最高优先级
第四行
接下来
user root
根据上述分析,调用&ServiceParser::ParseUser函数
Result<void> ServiceParser::ParseUser(std::vector<std::string>&& args) {
auto uid = DecodeUid(args[1]);
if (!uid.ok()) {
return Error() << "Unable to find UID for '" << args[1] << "': " << uid.error();
}
service_->proc_attr_.uid = *uid;
return {};
}
设置对应的service_->proc_attr_.uid
第五行
接下来
group root readproc reserved_disk
根据此前分析,此处调用ServiceParser::ParseGroup
Result<void> ServiceParser::ParseGroup(std::vector<std::string>&& args) {
// 解析gid
auto gid = DecodeUid(args[1]);
if (!gid.ok()) {
return Error() << "Unable to decode GID for '" << args[1] << "': " << gid.error();
}
// 设置service_->proc_attr_.gid
service_->proc_attr_.gid = *gid;
for (std::size_t n = 2; n < args.size(); n++) {
gid = DecodeUid(args[n]);
if (!gid.ok()) {
return Error() << "Unable to decode GID for '" << args[n] << "': " << gid.error();
}
// 解析对应的service_->proc_attr_.supp_gids
service_->proc_attr_.supp_gids.emplace_back(*gid);
}
return {};
}
如上,解析对应的service_->proc_attr_.gid和service_->proc_attr_.supp_gids
第六-七行
接下来
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
同一个socket开头的字段,调用ServiceParser::ParseSocket
Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
SocketDescriptor socket;
// 设置socket的名称
socket.name = std::move(args[1]);
// 设置socket的type
auto types = Split(args[2], "+");
if (types[0] == "stream") {
socket.type = SOCK_STREAM;
} else if (types[0] == "dgram") {
socket.type = SOCK_DGRAM;
} else if (types[0] == "seqpacket") {
socket.type = SOCK_SEQPACKET;
} else {
return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket', got '" << types[0]
<< "' instead.";
}
if (types.size() > 1) {
if (types.size() == 2 && types[1] == "passcred") {
socket.passcred = true;
} else {
return Error() << "Only 'passcred' may be used to modify the socket type";
}
}
errno = 0;
char* end = nullptr;
// socket.perm
socket.perm = strtol(args[3].c_str(), &end, 8);
if (errno != 0) {
return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
}
if (end == args[3].c_str() || *end != '\0') {
errno = EINVAL;
return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
}
if (args.size() > 4) {
// 解析socket.uid
auto uid = DecodeUid(args[4]);
if (!uid.ok()) {
return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error();
}
socket.uid = *uid;
}
if (args.size() > 5) {
// 解析socket.gid
auto gid = DecodeUid(args[5]);
if (!gid.ok()) {
return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error();
}
socket.gid = *gid;
}
// 此处无第7个参数
socket.context = args.size() > 6 ? args[6] : "";
auto old = std::find_if(service_->sockets_.begin(), service_->sockets_.end(),
[&socket](const auto& other) { return socket.name == other.name; });
if (old != service_->sockets_.end()) {
return Error() << "duplicate socket descriptor '" << socket.name << "'";
}
service_->sockets_.emplace_back(std::move(socket));
return {};
}
解析service_->sockets_
第八-十四行
onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
由前述可致,调用ServiceParser::ParseOnrestart
Result<void> ServiceParser::ParseOnrestart(std::vector<std::string>&& args) {
args.erase(args.begin());
int line = service_->onrestart_.NumCommands() + 1;
if (auto result = service_->onrestart_.AddCommand(std::move(args), line); !result.ok()) {
return Error() << "cannot add Onrestart command: " << result.error();
}
return {};
}
添加命令行到service_->onrestart_中,onrestart_是一个Action对象
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();
}
commands_.emplace_back(map_result->function, map_result->run_in_subcontext, std::move(args),
line);
return {};
}
即,将对应的操作函数添加到对应的service_->onrestart_->commands_中,此问题后续再行分析
第十五行
task_profiles ProcessCapacityHigh
同样地,调用ServiceParser::ParseTaskProfiles
Result<void> ServiceParser::ParseTaskProfiles(std::vector<std::string>&& args) {
args.erase(args.begin());
service_->task_profiles_ = std::move(args);
return {};
}
设置service_->task_profiles_参数
第十六行
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
调用ServiceParser::ParseCritical
Result<void> ServiceParser::ParseCritical(std::vector<std::string>&& args) {
std::optional<std::string> fatal_reboot_target;
std::optional<std::chrono::minutes> fatal_crash_window;
for (auto it = args.begin() + 1; it != args.end(); ++it) {
auto arg = android::base::Split(*it, "=");
if (arg.size() != 2) {
return Error() << "critical: Argument '" << *it << "' is not supported";
// 第二个参数为target
} else if (arg[0] == "target") {
// 设置fatal_reboot_target为”zygote-fatal”
fatal_reboot_target = arg[1];
// 第一个参数为windows,解析zygote.critical_window.minute为off,并设置属性值
} else if (arg[0] == "window") {
int minutes;
auto window = ExpandProps(arg[1]);
if (!window.ok()) {
return Error() << "critical: Could not expand argument ': " << arg[1];
}
// 此处直接返回
if (*window == "off") {
return {};
}
if (!ParseInt(*window, &minutes, 0)) {
return Error() << "critical: 'fatal_crash_window' must be an integer > 0";
}
fatal_crash_window = std::chrono::minutes(minutes);
} else {
return Error() << "critical: Argument '" << *it << "' is not supported";
}
}
if (fatal_reboot_target) {
service_->fatal_reboot_target_ = *fatal_reboot_target;
}
if (fatal_crash_window) {
service_->fatal_crash_window_ = *fatal_crash_window;
}
service_->flags_ |= SVC_CRITICAL;
return {};
}
设置service_->fatal_reboot_target_为”zygote-fatal”
结束
最后会调用结束时会返回一个T_EOF,会调用ServiceParser的EndSection函数(由于ServiceParser未定义EndFile函数,无需分析)
Result<void> ServiceParser::EndSection() {
......
// 查找是否已经有包含对应的Service对象,此处由于是第一次添加,service_list_中肯定是没有的
Service* old_service = service_list_->FindService(service_->name());
if (old_service) {
......
}
// 将刚刚创建的Service对象,通过AddService保存到ServiceManager中
service_list_->AddService(std::move(service_));
return {};
}
可以看到,最终将将刚刚创建的Service对象,通过AddService保存到ServiceManager
void ServiceList::AddService(std::unique_ptr<Service> service) {
services_.emplace_back(std::move(service));
}
即保存在Service的service_数组中
结论
ServiceParser解析工具解析配置文件,会将对应的配置文件的数据解析成一个Service对象,然后将其添加到ServiceManager中进行管理
ActionParser解析工具
初始化
根据前述,ActionParser的初始化如下
此处需要注意的是,ActionParser在map中的对应的字段为”on”
std::make_unique<ActionParser>(&action_manager, GetSubcontext())
对应的ActionParser构造函数
ActionParser(ActionManager* action_manager, Subcontext* subcontext)
: action_manager_(action_manager), subcontext_(subcontext), action_(nullptr) {}
可以看到,此处主要是给ActionParser对象中参数赋值
解析流程
解析流程,需要有一个解析文件来配合解析,此处,我们看下init.usb.rc配置文件的内容,查看init.usb.rc配置文件的内容,此处我们仅看前一段的数据解析
on post-fs-data
chown system system /sys/class/android_usb/android0/f_mass_storage/lun/file
chmod 0660 /sys/class/android_usb/android0/f_mass_storage/lun/file
chown system system /sys/class/android_usb/android0/f_rndis/ethaddr
chmod 0660 /sys/class/android_usb/android0/f_rndis/ethaddr
mkdir /data/misc/adb 02750 system shell
mkdir /data/adb 0700 root root encryption=Require
# adbd is controlled via property triggers in init.<platform>.usb.rc
service adbd /system/bin/adbd --root_seclabel=u:r:su:s0
class core
socket adbd seqpacket 660 system system
disabled
updatable
seclabel u:r:adbd:s0
on property:vendor.sys.usb.adb.disabled=*
setprop sys.usb.adb.disabled ${vendor.sys.usb.adb.disabled}
# Set default value on sys.usb.configfs early in boot sequence. It will be
# overridden in `on boot` action of init.hardware.rc.
on init
setprop sys.usb.configfs 0
......
根据此前的分析,Parser在解析的过程中,会按行解析,遇到字母字符,则将对应的字符串存入到args字符串数组中,那么对于init.usb.rc文件的
第一行
on post-fs-data
根据此前的分析Parser解析到这一行的时候,会将上述两个字符串分别放入到args字符串数组中,然后通过第一个字符串”on”找到此处的解析工具ActionParser对象,并调用其ParseSection函数
Result<void> ActionParser::ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) {
// 将args数据存放到triggers字符串数组中,此处解析triggers中只有一个元素,即post-fs-data
std::vector<std::string> triggers(args.begin() + 1, args.end());
if (triggers.size() < 1) {
return Error() << "Actions must have a trigger";
}
Subcontext* action_subcontext = nullptr;
// 判断当前文件地址是否存在于/vendor或者/odm里,此处当然不是,则action_subcontext为nullptr
if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
action_subcontext = subcontext_;
}
std::string event_trigger;
std::map<std::string, std::string> property_triggers;
// 调用ParseTriggers函数
if (auto result =
ParseTriggers(triggers, action_subcontext, &event_trigger, &property_triggers);
!result.ok()) {
return Error() << "ParseTriggers() failed: " << result.error();
}
// 初始化一个Action对象
auto action = std::make_unique<Action>(false, action_subcontext, filename, line, event_trigger,
property_triggers);
// 最后设置action_为刚刚创建的Action
action_ = std::move(action);
return {};
}
由上述代码可以看到,这边
首先调用了ActionParser的ParseTriggers函数
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循环查看每一个传入的参数
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 {
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 {};
}
从上述可知,在此处,主要是让event_trigger指向args[0]所代表的数据,即post-fs-data
其次初始化了一个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),
line_(line) {}
从传入参数来看,此处主要给Action的各项参数赋值
Oneshot_赋值为false
event_trigger_赋值为刚刚传入的字符串地址,其数值为post-fs-data
subcontext_赋值为前文中初始化的Subcontext对象
filename_为配置文件地址
line_表明这是第几行
第二行
chown system system /sys/class/android_usb/android0/f_mass_storage/lun/file
解析这一句话,此处我们知道chown没有对应的解析工具,而刚刚在第一行解析的时候,已经设置了section_parser对象为ActionParser对象,因此此处调用ActionParser的ParseLineSection函数,其参数为上述的各项字符串
Result<void> ActionParser::ParseLineSection(std::vector<std::string>&& args, int line) {
return action_ ? action_->AddCommand(std::move(args), line) : Result<void>{};
}
此前可知action_我们刚刚已经创建了,因此此处调用其AddCommand函数
Result<void> Action::AddCommand(std::vector<std::string>&& args, int line) {
if (!function_map_) {
return Error() << "no function map available";
}
// 从function_map_中查找参数所对应的函数
auto map_result = function_map_->Find(args);
// 若未找到对应的解析函数,则直接退出
if (!map_result.ok()) {
return Error() << map_result.error();
}
// 将对应的函数,以及参数存放到对应的命令行数组中
commands_.emplace_back(map_result->function, map_result->run_in_subcontext, std::move(args),
line);
return {};
}
这段代码可知,主要是将此处的命令加入到Action的命令行数组中,那么function_map是什么?这个在系统启动的过程中,有通过Action::set_function_map设置过,我们重温一下这个map
// 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 = {
{"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;
}
从这个map中,我们可以找到对应的chown的运行函数为do_chown函数,此处我们不做过多解析,通过名称可知,这是改变文件权限的
第三-七行
通过上述对于第二行的解析可以看到,此处会给Aciton对象的commands_命令行数组中添加一些命令
第十-十五行
通过此前对于ServiceParser的解析可知,此处主要创建一个Service对象,然后添加到ServiceManager中进行管理
但是,在此处,由于此前ActionParser在解析的过程中没有遇到T_EOF,那么对应的Action对象是如何来保存的呢?
这个就用到此前分析过的end_section函数,这个函数我们此前分析过,主要是当遇到T_EOF的时候或者当遇到下一个SectionParser的时候,会调用到它,且在这个函数中,主要是调用了对应的section_parser的EndSection函数,那么对于init.usb.rc文件来说,遇到下一个ServiceParser之前,会调用ActionParser::EndSection
Result<void> ActionParser::EndSection() {
if (action_ && action_->NumCommands() > 0) {
action_manager_->AddAction(std::move(action_));
}
return {};
}
也即,将在第一行中创建的Action对象添加到ActionManager中进行管理
void ActionManager::AddAction(std::unique_ptr<Action> action) {
actions_.emplace_back(std::move(action));
}
可以看到,此处将Action对象添加到ActionManager的action_参数数组中
第十七-十八行
on property:vendor.sys.usb.adb.disabled=*
setprop sys.usb.adb.disabled ${vendor.sys.usb.adb.disabled}
此处与第一行的Action解析不同的地方在于ParserTriggers中,由于此处解析的args是以property:开头,因此会调用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:");
// 获取proterty:后续的字符串
std::string prop_name(trigger.substr(prop_str.length()));
// 判断字符串中是否有包含’=’字符
size_t equal_pos = prop_name.find('=');
if (equal_pos == std::string::npos) {
return Error() << "property trigger found without matching '='";
}
// 解析属性值名称为vendor.sys.usb.adb.disabled,属性值为*
std::string prop_value(prop_name.substr(equal_pos + 1));
prop_name.erase(equal_pos);
// 由于此属性值名称以vendor开头,因此此处函数返回true
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对象,表明此行动项是以属性来触发,然后继续解析下一行,添加该行动项的命令行,最终,同上述解析一样,添加到ActionManager的action_行动项数组中
结论
触发ActionParser解析工具,则会解析出一个Action对象,这个Action包含很多的command,最后将这个Action对象添加到ActionManager
ImportParser解析工具
初始化
std::make_unique<ImportParser>(&parser)
直接初始化一个ImportParser对象
ImportParser(Parser* parser) : parser_(parser) {}
解析流程
这个我们使用init.rc文件来看下
import /init.environ.rc
import /system/etc/init/hw/init.usb.rc
import /init.${ro.hardware}.rc
在解析过程中,由前述可知,第一行,会触发ImportParser的ParserSection函数
Result<void> ImportParser::ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) {
if (args.size() != 2) {
return Error() << "single argument needed for import\n";
}
// 解析第二个参数
auto conf_file = ExpandProps(args[1]);
if (!conf_file.ok()) {
return Error() << "Could not expand import: " << conf_file.error();
}
LOG(INFO) << "Added '" << *conf_file << "' to import list";
if (filename_.empty()) filename_ = filename;
// 添加到imports_中
imports_.emplace_back(std::move(*conf_file), line);
return {};
}
首先解析第一个参数
Result<std::string> ExpandProps(const std::string& src) {
const char* src_ptr = src.c_str();
std::string dst;
/* - variables can either be $x.y or ${x.y}, in case they are only part
* of the string.
* - will accept $$ as a literal $.
* - no nested property expansion, i.e. ${foo.${bar}} is not supported,
* bad things will happen
* - ${x.y:-default} will return default value if property empty.
*/
while (*src_ptr) {
const char* c;
c = strchr(src_ptr, '$');
if (!c) {
dst.append(src_ptr);
return dst;
}
dst.append(src_ptr, c);
c++;
if (*c == '$') {
dst.push_back(*(c++));
src_ptr = c;
continue;
} else if (*c == '\0') {
return dst;
}
std::string prop_name;
std::string def_val;
if (*c == '{') {
c++;
const char* end = strchr(c, '}');
if (!end) {
// failed to find closing brace, abort.
return Error() << "unexpected end of string in '" << src << "', looking for }";
}
prop_name = std::string(c, end);
c = end + 1;
size_t def = prop_name.find(":-");
if (def < prop_name.size()) {
def_val = prop_name.substr(def + 2);
prop_name = prop_name.substr(0, def);
}
} else {
prop_name = c;
if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) {
return Error() << "using deprecated syntax for specifying property '" << c
<< "', use ${name} instead";
} else {
LOG(ERROR) << "using deprecated syntax for specifying property '" << c
<< "', use ${name} instead";
}
c += prop_name.size();
}
if (prop_name.empty()) {
return Error() << "invalid zero-length property name in '" << src << "'";
}
std::string prop_val = android::base::GetProperty(prop_name, "");
if (prop_val.empty()) {
if (def_val.empty()) {
return Error() << "property '" << prop_name << "' doesn't exist while expanding '"
<< src << "'";
}
prop_val = def_val;
}
dst.append(prop_val);
src_ptr = c;
}
return dst;
}
主要解析第二个参数文件地址中包含的属性名称对应的属性值,并替换到该字符串中 此后将所有import开头的配置数据均保存到import_数组中
那么在什么位置进行解析的呢? 还记得当配置文件解析完成的时候,会上报T_EOF给到Parser解析器么? 此时会调用所有配置文件解析工具的EndFile函数
void ImportParser::EndFile() {
auto current_imports = std::move(imports_);
imports_.clear();
for (const auto& [import, line_num] : current_imports) {
parser_->ParseConfig(import);
}
}
然后将所有的imports_包含的配置文件地址重新使用Parser的ParseConfig解析一遍
由此,可知,import开始的行,init.rc中,虽然是在文件开始的时候就添加了这个行,但是知道配置文件解析结束后,才会一一重新解析这些import的配置文件
结论
ImportParser解析工具,从名称中就可以看出,这个解析工具,主要是添加一些引入一些其他解析文件,最后一起解析的
解析工具总结
从如上的三种解析工具的分析,我们可知,在解析配置文件的最后,会将这些配置文件变为
- Service对象,添加到ServiceList的service_服务数组中进行统一管理
- Action对象,添加到ActionManager的actions_行动项数组中进行统一管理,同时Action对象还包含了一个个的命令行,保存在commands_数组中
- ImportParser解析工具的主要作用是,引入一个新的配置文件