android 配置启动参数,Android系统启动之配置文件解析

以下代码基于Android 7.0分析

简介

我们知道在Android系统启动的时候会创建Init进程,在Init进程的main()入口函数中会解析系统配置文件进行服务进程的创建和启动。

解析Init.rc配置文件

[->system/core/init/init.cpp]

int main(int argc, char** argv) {

...

//这里将Action的function_map_替换为BuiltinFunctionMap

//下文将通过BuiltinFuntionMap的map方法,获取keyword对应的处理函数

const BuiltinFunctionMap function_map;

Action::set_function_map(&function_map);

//构造出解析文件用的parser对象

Parser& parser = Parser::GetInstance();

//为一些类型的关键字,创建特定的parser

parser.AddSectionParser("service",std::make_unique());

parser.AddSectionParser("on", std::make_unique());

parser.AddSectionParser("import", std::make_unique());

//开始实际的解析过程

parser.ParseConfig("/init.rc");

...

}

在解析init.rc文件之前,我们先来简单的介绍一下init.rc文件。init.rc文件是在init进程启动后执行的启动脚本,文件中记录着init进程需执行的操作。在Android系统中,使用init.rc和init.{ hardware }.rc两个文件。

其中init.rc文件在Android系统运行过程中用于通用的环境设置与进程相关的定义,init.{hardware}.rc(例如,高通有init.qcom.rc,MTK有init.mediatek.rc)用于定义Android在不同平台下的特定进程和环境设置等。

此处的init.rc位于system/core/rootdir/init.rc中。

init.rc文件大致分为2部分,一部分是以"on"关键字开头的动作列表(action list):

on early-init

# Set init and its forked children's oom_adj.

write /proc/1/oom_score_adj -1000

.........

start ueventd

另一部分是以"service"关键字开头的服务列表(service list):

service ueventd /sbin/ueventd

class core

critical

seclabel u:r:ueventd:s0

借助系统环境变量或Linux命令,动作列表用于创建所需目录,以及为某些特定文件指定权限,而服务列表用来记录init进程需要启动的一系列子进程。如上面代码所示,service关键字后第一个字符串表示服务(子进程)的名称,第二个字符串表示服务的执行路径。

接下来我们就从ParseConfig函数入手,逐步分析整个解析过程。

[->system/core/init/ init_parser.cpp]

bool Parser::ParseConfig(const std::string& path) {

//path为/init.rc

if (is_dir(path.c_str())) {

//传入参数为目录地址

return ParseConfigDir(path);

}

//传入参数为文件地址

return ParseConfigFile(path);

}

bool Parser::ParseConfigDir(const std::string& path) {

...........

std::unique_ptr

..........

//看起来很复杂,其实就是递归目录

while ((current_file = readdir(config_dir.get()))) {

std::string current_path = android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);

if (current_file->d_type == DT_REG) {

//最终还是靠ParseConfigFile来解析实际的文件

if (!ParseConfigFile(current_path)) {

.............

}

}

}

}

bool Parser::ParseConfigFile(const std::string& path) {

........

std::string data;

//读取路径指定文件中的内容,保存为字符串形式

if (!read_file(path.c_str(), &data)) {

return false;

}

.........

//解析获取的字符串

ParseData(path, data);

.........

}

void Parser::ParseData(const std::string& filename, const std::string& data) {

.......

parse_state state;

.......

std::vector<:string> args;

for (;;) {

//next_token以行为单位分割参数传递过来的字符串

//最先走到T_TEXT分支

switch (next_token(&state)) {

case T_EOF:

if (section_parser) {

//EOF,解析结束

section_parser->EndSection();

}

return;

case T_NEWLINE:

state.line++;

if (args.empty()) {

break;

}

//在前文创建parser时,我们为service,on,import定义了对应的parser

//这里就是根据第一个参数,判断是否有对应的parser

if (section_parsers_.count(args[0])) {

if (section_parser) {

//结束上一个parser的工作,将构造出的对象加入到对应的service_list与action_list中

section_parser->EndSection();

}

//获取参数对应的parser

section_parser = section_parsers_[args[0]].get();

std::string ret_err;

//调用实际parser的ParseSection函数(重点)

if (!section_parser->ParseSection(args, &ret_err)) {

parse_error(&state, "%s\n", ret_err.c_str());

section_parser = nullptr;

}

} else if (section_parser) {

std::string ret_err;

//如果第一个参数不是service,on,import

//则调用前一个parser的ParseLineSection函数

//这里相当于解析一个参数块的子项

if (!section_parser->ParseLineSection(args, state.filename, state.line, &ret_err)) {

parse_error(&state, "%s\n", ret_err.c_str());

}

}

//清空本次解析的数据

args.clear();

break;

case T_TEXT:

//将本次解析的内容写入到args中

args.emplace_back(state.text);

break;

}

}

}

这里的解析看起来比较复杂,在6.0以前的版本中,整个解析是面向过程的。init进程统一调用一个函数来进行解析,然后在该函数中利用switch-case的形式,根据解析的内容进行相应的处理。

在Android 7.0中,为了更好地封装及面向对象,对于不同的关键字定义了不同的parser对象,每个对象通过多态实现自己的解析操作。

现在我们来回一下init进程main函数中创建的三个parse代码

Parser& parser = Parser::GetInstance();

parser.AddSectionParser("service",std::make_unique());

parser.AddSectionParser("on", std::make_unique());

parser.AddSectionParser("import", std::make_unique());

看下三个Parse的定义

class ServiceParser : public SectionParser {......}

class ActionParser : public SectionParser {......}

class ImportParser : public SectionParser {.......}

可以看到三个Parser均是继承SectionParser,具体的实现各有不同,我们以比较常用的ServiceParser和ActionParser为例,看看解析的结果如何处理。

ServiceParser

ServiceParser定义在system/core/init/service.cpp中。从前面的代码中我们知道,解析一个service块,首先需要调用ParseSection函数,接着你用ParseLineSection处理子块,在解析完数据后,调用EndSection。

因此,我们就着重来看下这三个函数。

[->system/core/init/service.cpp]

//根据参数来构造一个service对象

bool ServiceParser::ParseSection(.....) {

.......

const std::string& name = args[1];

.......

std::vector<:string> str_args(args.begin() + 2, args.end());

//主要根据参数,构造出一个service对象

service_ = std::make_unique(name, "default", str_args);

return true;

}

//注意这里已经在解析子项了

bool ServiceParser::ParseLineSection(......) const {

//调用service对象的HandleLine

return service_ ? service_->HandleLine(args, err) : false;

}

bool Service::HandleLine(.....) {

........

//OptionHandlerMap继承自keywordMap

static const OptionHandlerMap handler_map;

//根据子项的内容,找到对应的handler函数

//FindFunction定义与keyword模块中,FindFunction方法利用子类生成对应的map中,然后通过通用的查找方法,即比较键值找到对应的处理函数

auto handler = handler_map.FindFunction(args[0], args.size() - 1, err);

if (!handler) {

return false;

}

//调用handler函数

return (this->*handler)(args, err);

}

class Service::OptionHandlerMap : public KeywordMap {

...........

Service::OptionHandlerMap::Map& Service::OptionHandlerMap::map() const {

constexpr std::size_t kMax = std::numeric_limits<:size_t>::max();

static const Map option_handlers = {

{"class", {1, 1, &Service::HandleClass}},

{"console", {0, 0, &Service::HandleConsole}},

{"critical", {0, 0, &Service::HandleCritical}},

{"disabled", {0, 0, &Service::HandleDisabled}},

{"group", {1, NR_SVC_SUPP_GIDS + 1, &Service::HandleGroup}},

{"ioprio", {2, 2, &Service::HandleIoprio}},

{"keycodes", {1, kMax, &Service::HandleKeycodes}},

{"oneshot", {0, 0, &Service::HandleOneshot}},

{"onrestart", {1, kMax, &Service::HandleOnrestart}},

{"seclabel", {1, 1, &Service::HandleSeclabel}},

{"setenv", {2, 2, &Service::HandleSetenv}},

{"socket", {3, 6, &Service::HandleSocket}},

{"user", {1, 1, &Service::HandleUser}},

{"writepid", {1, kMax, &Service::HandleWritepid}},

};

return option_handlers;

}

//以class对应的处理函数为例,可以看出其实就是填充service对象对应的域

bool Service::HandleClass(const std::vector<:string>& args, std::string* err) {

classname_ = args[1];

return true;

}

//注意此时service对象已经处理完毕

void ServiceParser::EndSection() {

if (service_) {

ServiceManager::GetInstance().AddService(std::move(service_));

}

}

void ServiceManager::AddService(std::unique_ptr service) {

Service* old_service = FindServiceByName(service->name());

if (old_service) {

ERROR("ignored duplicate definition of service '%s'",

service->name().c_str());

return;

}

//将service对象加入到services_里

//7.0里,services_已经是个vector了

services_.emplace_back(std::move(service));

}

从上面的一系列代码,我们可以看出ServiceParser其实就是:首先根据第一行的名字和参数创建出service对象,然后根据选项域的内容填充service对象,最后将创建出的service对象加入到vector类型的service链表中。

ActionParser

ActionParser定义于system/core/init/action.cpp中。Action的解析过程,其实与Service一样,也是先后调用ParseSection, ParseLineSection和EndSection。

[->system/core/init/action.cpp]

bool ActionParser::ParseSection(....) {

........

//创建出新的action对象

auto action = std::make_unique(false);

//根据参数,填充action的trigger域,不详细分析了

if (!action->InitTriggers(triggers, err)) {

return false;

}

.........

}

bool ActionParser::ParseLineSection(.......) const {

//构造Action对象的command域

return action_ ? action_->AddCommand(args, filename, line, err) : false;

}

bool Action::AddCommand(.....) {

........

//找出action对应的执行函数

auto function = function_map_->FindFunction(args[0], args.size() - 1, err);

........

//利用所有信息构造出command,加入到action对象中

AddCommand(function, args, filename, line);

return true;

}

void Action::AddCommand(......) {

commands_.emplace_back(f, args, filename, line);

}

void ActionParser::EndSection() {

if (action_ && action_->NumCommands() > 0) {

ActionManager::GetInstance().AddAction(std::move(action_));

}

}

void ActionManager::AddAction(.....) {

........

auto old_action_it = std::find_if(actions_.begin(),

actions_.end(),

[&action] (std::unique_ptr& a) {

return action->TriggersEqual(*a);

});

if (old_action_it != actions_.end()) {

(*old_action_it)->CombineAction(*action);

} else {

//加入到action链表中,类型也是vector,其中装的是指针

actions_.emplace_back(std::move(action));

}

}

从上面的代码可以看出,加载action块的逻辑和service一样,不同的是需要填充trigger和command域。当然,最后解析出的action也需要加入到action链表中。

这里最后还剩下一个问题,那就是哪里定义了Action中command对应处理函数?

实际上,前文已经出现了过了,在init.cpp的main函数中:

const BuiltinFunctionMap function_map;

Action::set_function_map(&function_map);

因此,Action中调用function_map->FindFunction时,实际上调用的是BuiltinFunctionMap的FindFunction函数。我们已经知道FindFunction是keyword定义的通用函数,重点是重构的map函数。我们看看system/core/init/builtins.cpp:

BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {

constexpr std::size_t kMax = std::numeric_limits<:size_t>::max();

static const Map builtin_functions = {

{"bootchart_init", {0, 0, do_bootchart_init}},

{"chmod", {2, 2, do_chmod}},

{"chown", {2, 3, do_chown}},

{"class_reset", {1, 1, do_class_reset}},

{"class_start", {1, 1, do_class_start}},

{"class_stop", {1, 1, do_class_stop}},

{"copy", {2, 2, do_copy}},

{"domainname", {1, 1, do_domainname}},

{"enable", {1, 1, do_enable}},

{"exec", {1, kMax, do_exec}},

{"export", {2, 2, do_export}},

{"hostname", {1, 1, do_hostname}},

{"ifup", {1, 1, do_ifup}},

{"init_user0", {0, 0, do_init_user0}},

{"insmod", {1, kMax, do_insmod}},

{"installkey", {1, 1, do_installkey}},

{"load_persist_props", {0, 0, do_load_persist_props}},

{"load_system_props", {0, 0, do_load_system_props}},

{"loglevel", {1, 1, do_loglevel}},

{"mkdir", {1, 4, do_mkdir}},

{"mount_all", {1, kMax, do_mount_all}},

{"mount", {3, kMax, do_mount}},

{"powerctl", {1, 1, do_powerctl}},

{"restart", {1, 1, do_restart}},

{"restorecon", {1, kMax, do_restorecon}},

{"restorecon_recursive", {1, kMax, do_restorecon_recursive}},

{"rm", {1, 1, do_rm}},

{"rmdir", {1, 1, do_rmdir}},

{"setprop", {2, 2, do_setprop}},

{"setrlimit", {3, 3, do_setrlimit}},

{"start", {1, 1, do_start}},

{"stop", {1, 1, do_stop}},

{"swapon_all", {1, 1, do_swapon_all}},

{"symlink", {2, 2, do_symlink}},

{"sysclktz", {1, 1, do_sysclktz}},

{"trigger", {1, 1, do_trigger}},

{"verity_load_state", {0, 0, do_verity_load_state}},

{"verity_update_state", {0, 0, do_verity_update_state}},

{"wait", {1, 2, do_wait}},

{"write", {2, 2, do_write}},

};

return builtin_functions;

}

上面代码的每项的最后一项就是Action中每个command所对应的执行函数。

向执行队列中添加其他action

介绍完init进程解析init.rc文件的过程后,我们继续将视角拉回到init进程的main函数:

ActionManager& am = ActionManager::GetInstance();

am.QueueEventTrigger("early-init");

// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...

m.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");

// ... so that we can start queuing up actions that require stuff from /dev.

am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");

am.QueueBuiltinAction(keychord_init_action, "keychord_init");

am.QueueBuiltinAction(console_init_action, "console_init");

// Trigger all the boot actions to get us started.

am.QueueEventTrigger("init");

// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random

// wasn't ready immediately after wait_for_coldboot_done

am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

// Don't mount filesystems or start core system services in charger mode.

std::string bootmode = property_get("ro.bootmode");

if (bootmode == "charger") {

am.QueueEventTrigger("charger");

} else {

am.QueueEventTrigger("late-init");

}

// Run all property triggers based on current state of the properties.

am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

从上面的代码可以看出,接下来init进程中调用了大量的QueueEventTrigger和QueueBuiltinAction函数。

void ActionManager::QueueEventTrigger(const std::string& trigger) {

trigger_queue_.push(std::make_unique(trigger));

}

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

//创建action

auto action = std::make_unique(true);

std::vector<:string> name_vector{name};

//保证唯一性

if (!action->InitSingleTrigger(name)) {

return;

}

//创建action的cmd,指定执行函数和参数

action->AddCommand(func, name_vector);

trigger_queue_.push(std::make_unique(action.get()));

actions_.emplace_back(std::move(action));

}

此处QueueEventTrigger函数就是利用参数构造EventTrigger,然后加入到trigger_queue_中。后续init进程处理trigger事件时,将会触发相应的操作。根据前文的分析,我们知道实际上就是将action_list中,对应trigger与第一个参数匹配的action,加入到运行队列action_queue中。

QueueBuiltinAction函数中构造新的action加入到actions_中,第一个参数作为新建action携带cmd的执行函数;第二个参数既作为action的trigger name,也作为action携带cmd的参数。

继续main函数主流程

while (true) {

//判断是否有事件需要处理

if (!waiting_for_exec) {

//依次执行每个action中携带command对应的执行函数

am.ExecuteOneCommand();

//重启一些挂掉的进程

restart_processes();

}

//以下决定timeout的时间,将影响while循环的间隔

int timeout = -1;

//有进程需要重启时,等待该进程重启

if (process_needs_restart) {

timeout = (process_needs_restart - gettime()) * 1000;

if (timeout < 0)

timeout = 0;

}

//有action待处理,不等待

if (am.HasMoreCommands()) {

timeout = 0;

}

//bootchart_sample应该是进行性能数据采样

bootchart_sample(&timeout);

epoll_event ev;

//没有事件到来的话,最多阻塞timeout时间

int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));

if (nr == -1) {

ERROR("epoll_wait failed: %s\n", strerror(errno));

} else if (nr == 1) {

//有事件到来,执行对应处理函数

//根据上文知道,epoll句柄(即epoll_fd)主要监听子进程结束,及其它进程设置系统属性的请求。

((void (*)()) ev.data.ptr)();

}

}

从上面代码可以看出,init进程将所有需要操作的action加入运行队列后, 进入无限循环过程,不断处理运行队列中的事件,同时进行重启service等操作。

ExecuteOneCommand中的主要部分如下图所示:

void ActionManager::ExecuteOneCommand() {

// Loop through the trigger queue until we have an action to execute

//当有可执行action或trigger queue为空时结束

while (current_executing_actions_.empty() && !trigger_queue_.empty()) {

//轮询actions链表

for (const auto& action : actions_) {

//依次查找trigger表

if (trigger_queue_.front()->CheckTriggers(*action)) {

//当action与trigger对应时,就可以执行当前action

//一个trigger可以对应多个action,均加入current_executing_actions_

current_executing_actions_.emplace(action.get());

}

}

//trigger event出队

trigger_queue_.pop();

}

if (current_executing_actions_.empty()) {

return;

}

//每次只执行一个action,下次init进程while循环时,跳过上面的while循环,接着执行

auto action = current_executing_actions_.front();

if (current_command_ == 0) {

std::string trigger_name = action->BuildTriggersString();

INFO("processing action (%s)\n", trigger_name.c_str());

}

//实际的执行过程,此处仅处理当前action中的一个cmd

action->ExecuteOneCommand(current_command_);

//适当地清理工作,注意只有当前action中所有的command均执行完毕后,才会将该action从current_executing_actions_移除

// 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& a) {

return a.get() == action;

};

actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));

}

}

}

void Action::ExecuteCommand(const Command& command) const {

Timer t;

//执行该command对应的处理函数

int result = command.InvokeFunc();

........

}

从代码可以看出,当while循环不断调用ExecuteOneCommand函数时,将按照trigger表的顺序,依次取出action链表中与trigger匹配的action。

每次均执行一个action中的一个command对应函数(一个action可能携带多个command)。

当一个action所有的command均执行完毕后,再执行下一个action。

当一个trigger对应的action均执行完毕后,再执行下一个trigger对应action。

restart_processes函数负责按需重启service,代码如下所示:

static void restart_processes() {

process_needs_restart = 0;

ServiceManager::GetInstance().ForEachServiceWithFlags(

SVC_RESTARTING,

[] (Service* s) {

s->RestartIfNeeded(process_needs_restart);

});

}

从上面可以看出,该函数轮询service对应的链表,对于有SVC_RESTARING标志的service执行RestartIfNeeded(如上文所述,当子进程终止时,init进程会将可被重启进程的服务标志位置为SVC_RESTARTING)。

如下代码所示,restart_service_if_needed可以重新启动服务:

void Service::RestartIfNeeded(time_t& process_needs_restart)(struct service *svc)

{

time_t next_start_time = svc->time_started + 5;

//两次服务启动时间的间隔要大于5s

if (next_start_time <= gettime()) {

svc->flags &= (~SVC_RESTARTING);

//满足时间间隔的要求后,重启服务

//Start将会重新fork服务进程,并做相应的配置

Start(svc, NULL);

return;

}

//更新main函数中,while循环需要等待的时间

if ((next_start_time < process_needs_restart) ||

(process_needs_restart == 0)) {

process_needs_restart = next_start_time;

}

}

总结

关于配置文件的解析Android6.0和7.0整体的流程几乎不变,但7.0为了更好的封装性,修改了解析文件后存储用的数据结构,同时引入了一些多态相关的内容。

虽然人要往后看,但6.0中还是有很多有意思的地方,比如keywords.h的宏替换及利用listnode来组织通用的链表等。这部分内容,可以参阅一下《深入理解Android 卷I》,虽然书对应的代码比较老,但大体思想还是相似的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值