Android O: init进程启动流程分析(阶段三)
Posted ZhangJianIsAStark
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android O: init进程启动流程分析(阶段三)相关的知识,希望对你有一定的参考价值。
在前面的博客Android O: init进程启动流程分析(阶段一)
和Android O: init进程启动流程分析(阶段二)中,
我们已经介绍过了init进程启动时的一些准备工作。
本篇博客我们就来看看init进程启动时,解析init.rc文件相关的工作。
一、创建Parser并决定解析文件
int main(int argc, char** argv)
..............
//定义Action中的function_map_为BuiltinFuntionMap
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
//构造出解析文件用的parser对象
Parser& parser = Parser::GetInstance();
//为一些类型的关键字,创建特定的parser
parser.AddSectionParser("service",std::make_unique<ServiceParser>());
parser.AddSectionParser("on", std::make_unique<ActionParser>());
parser.AddSectionParser("import", std::make_unique<ImportParser>());
//判断是否存在bootscript
std::string bootscript = GetProperty("ro.boot.init_rc", "");
//如果没有bootscript,则解析init.rc文件
if (bootscript.empty())
parser.ParseConfig("/init.rc");
parser.set_is_system_etc_init_loaded(
parser.ParseConfig("/system/etc/init"));
parser.set_is_vendor_etc_init_loaded(
parser.ParseConfig("/vendor/etc/init"));
parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
else
//若存在bootscript, 则解析bootscript
parser.ParseConfig(bootscript);
parser.set_is_system_etc_init_loaded(true);
parser.set_is_vendor_etc_init_loaded(true);
parser.set_is_odm_etc_init_loaded(true);
.........
........
从上面的代码来看,8.0引入了bootScript的概念,
个人感觉这个应该是方便厂商的定制吧。
如果没有定义bootScript,那么init进程还是会解析init.rc文件。
init.rc文件是在init进程启动后执行的启动脚本,文件中记录着init进程需执行的操作。
此处解析函数传入的参数为“/init.rc”,解析的是运行时与init进程同在根目录下的init.rc文件。
该文件在编译前,定义于system/core/rootdir/init.rc中。
init.rc文件大致分为两大部分,一部分是以“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函数
接下来,我们从Parser的ParseConfig函数入手,逐步分析整个文件解析的过程。
ParseConfig函数定义于system/core/init/ init_parser.cpp中:
bool Parser::ParseConfig(const std::string& path)
if (is_dir(path.c_str()))
//传入参数为目录地址
return ParseConfigDir(path);
//传入参数为文件地址
return ParseConfigFile(path);
我们先来看看ParseConfigDir函数:
bool Parser::ParseConfigDir(const std::string& path)
...........
std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir);
..........
//递归目录,得到需要处理的文件
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)
//容易看出,最终仍是调用ParseConfigFile
if (!ParseConfigFile(file))
LOG(ERROR) << "could not import file '" << file << "'";
return true;
我们跟进一下ParseConfigFile函数:
bool Parser::ParseConfigFile(const std::string& path)
........
Timer t;
std::string data;
//读取路径指定文件中的内容,保存为字符串形式
if (!read_file(path, &data))
return false;
.........
//解析获取的字符串
ParseData(path, data);
.........
return true;
容易看出,ParseConfigFile只是读取文件的内容并转换为字符串。
实际的解析工作被交付给ParseData。
三、ParseData函数
ParseData函数定义于system/core/init/init_parser.cpp中,负责根据关键字解析出服务和动作。
动作与服务会以链表节点的形式注册到service_list与action_list中,
service_list与action_list是init进程中声明的全局结构体。
ParseData的关键代码下所示:
void Parser::ParseData(const std::string& filename, const std::string& data)
//TODO: Use a parser with const input and remove this copy
//copy一波数据
std::vector<char> data_copy(data.begin(), data.end());
data_copy.push_back('\\0');
//解析用的结构体
parse_state state;
state.filename = filename.c_str();
state.line = 0;
state.ptr = &data_copy[0];
state.nexttoken = 0;
SectionParser* section_parser = nullptr;
std::vector<std::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)
//如果新的一行,第一个参数不是service,on,import
//则调用前一个parser的ParseLineSection函数
//这里相当于解析一个参数块的子项
std::string ret_err;
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;
上面的代码看起来比较复杂,但实际上就是面向对象,根据不同的关键字,
使用不同的parser对象进行解析。
我们现在回忆一下init进程main函数中,创建parser的代码:
...........
Parser& parser = Parser::GetInstance();
parser.AddSectionParser("service",std::make_unique<ServiceParser>());
parser.AddSectionParser("on", std::make_unique<ActionParser>());
parser.AddSectionParser("import", std::make_unique<ImportParser>());
...........
三种Parser均是继承SectionParser,具体的实现各有不同。
接下来,我们以比较常用的ServiceParser和ActionParser为例,
看看解析的结果如何处理。
3.1、ServiceParser
ServiceParser定义于system/core/init/service.cpp中。
从前面的代码我们知道,解析一个service块时,首先需要调用ParseSection函数,
接着利用ParseLineSection处理子块,解析完所有数据后,最后调用EndSection。
因此,我们着重看看ServiceParser的这三个函数。
3.1.1、ParseSection
bool ServiceParser::ParseSection(.....)
//参数检验
.......
//服务名
const std::string& name = args[1];
//服务名校验
if (!IsValidName(name))
*err = StringPrintf("invalid service name '%s'", name.c_str());
return false;
std::vector<std::string> str_args(args.begin() + 2, args.end());
//构造出一个service对象
service_ = std::make_unique<Service>(name, str_args);
return true;
ParseSection主要校验参数的有效性,并创建出Service结构体。
3.1.2、ParseLineSection
//注意这里已经在解析子项了
bool ServiceParser::ParseLineSection(......) const
//调用service对象的HandleLine
return service_ ? service_->ParseLine(args, err) : false;
我们跟进一下ParseLine函数:
bool Service::ParseLine(.....)
//参数校验
........
//OptionParserMap继承自keywordMap<OptionParser>
static const OptionParserMap parser_map;
//根据子项的内容,找到对应的处理函数
//FindFunction利用OptionParserMap的map,根据参数找到对应的处理函数
auto parser = parser_map.FindFunction(args[0], args.size() - 1, err);
if (!parser)
return false;
//调用对应的处理函数
return (this->*parser)(args, err);
为了了解这部分内容,我们需要看看OptionParserMap中的map函数:
class Service::OptionParserMap : public KeywordMap<OptionParser>
...........
Service::OptionHandlerMap::Map& Service::OptionHandlerMap::map() const
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
//定义了各种关键子对应的处理函数
static const Map option_parsers =
"capabilities", 1, kMax, &Service::ParseCapabilities,
"class", 1, 1, &Service::ParseClass,
.....................
;
return option_parsers;
.......
我们以class对应的处理函数为例,看看对应的代码:
bool Service::ParseClass(const std::vector<std::string>& args, std::string* err)
classnames_ = std::set<std::string>(args.begin() + 1, args.end());
return true;
容易看出,这部分代码其实就是填充service对象对应的域。
因此,可以推断ParseLineSection函数的作用,
就是根据关键字填充Service对象。
3.1.3、EndSection
最后,我们来看看EndSection函数的流程:
//注意此时service对象已经构造完毕
void ServiceParser::EndSection()
if (service_)
ServiceManager::GetInstance().AddService(std::move(service_));
我们继续跟进AddService函数:
void ServiceManager::AddService(std::unique_ptr<Service> service)
Service* old_service = FindServiceByName(service->name());
//处理尴尬的重复定义
if (old_service)
LOG(ERROR) << "ignored duplicate definition of service '" << service->name() << "'";
return;
//将service对象加入到services_里
services_.emplace_back(std::move(service));
从上面的一系列代码,我们可以看出ServiceParser的工作流程就是:
首先,根据第一行的名字和参数创建出service对象;
然后,根据子项的内容填充service对象;
最后,将创建出的service对象加入到vector类型的service链表中。
3.2、ActionParser
ActionParser定义于system/core/init/action.cpp中。
Action的解析过程,其实与Service一样,也是先后调用ParseSection, ParseLineSection和EndSection。
3.2.1、ParseSection
bool ActionParser::ParseSection(....)
//构造trigger
std::vector<std::string> triggers(args.begin() + 1, args.end());
if (triggers.size() < 1)
*err = "actions must have a trigger";
return false;
//创建出新的action对象
auto action = std::make_unique<Action>(false);
//根据参数,填充action的trigger域,不详细分析了
if (!action->InitTriggers(triggers, err))
return false;
action_ = std::move(action);
return true;
与Service类似,Action的ParseSection函数用于构造出Action对象。
3.2.2、ParseLineSection
bool ActionParser::ParseLineSection(.....) const
//构造Action对象的command域
return action_ ? action_->AddCommand(args, filename, line, err) : false;
ParseLineSection将解析Action的子项,构造出Action对象的command域。
我们进一步看看AddCommand函数:
bool Action::AddCommand(const std::vector<std::string>& args,
const std::string& filename, int line, std::string* err)
........
//找出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);
不难看出ParseLineSection主要是根据参数填充Action的command域。
一个Action对象中可以有多个command。
这里还剩下一个问题:Action中的function_map_是什么?
实际上,前文已经出现了过了,在init.cpp的main函数中:
.......
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
.......
因此,Action中调用function_map_->FindFunction时,
实际上调用的是BuiltinFunctionMap的FindFunction函数。
与查找Service一样,这里也是根据键值查找对应的信息,
因此重点是看看BuiltinFunctionMap的map函数。
在system/core/init/builtins.cpp中:
BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
static const Map builtin_functions =
"bootchart", 1, 1, do_bootchart,
"chmod", 2, 2, do_chmod,
..................
;
return builtin_functions;
上述代码的第四项就是Action每个command对应的执行函数。
3.2.3、EndSection
void ActionParser::EndSection()
//Action有效时,才需要加入
if (action_ && action_->NumCommands() > 0)
ActionManager::GetInstance().AddAction(std::move(action_));
跟进AddAction函数:
void ActionManager::AddAction(.....)
//判断之前是否有定义过的Action
//判断的依据是Action的trigger域
auto auto old_action_it =
std::find_if(actions_.begin(), actions_.end(),
[&action] (std::unique_ptr<Action>& a)
return action->TriggersEqual(*a);
);
//相对于Service,Action包容性强一些
//重复定义时,会合并Action
if (old_action_it != actions_.end())
//主要是合并command
(*old_action_it)->CombineAction(*action);
else
//加入到action链表中,类型也是vector,其中装的是指针
actions_.emplace_back(std::move(action));
从上面的代码可以看出,加载action块的逻辑和service一样,不同的是需要填充trigger和command域。
当然,最后解析出的action也需要加入到action链表中。
四、向Action队列中添加其它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(set_kptr_restrict_action, "set_kptr_restrict");
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进程中调用了大量的QueueBuiltinAction和QueueEventTrigger函数。
接下来,我们就来看看这两个函数进行了哪些工作。
4.1、QueueBuiltinAction
QueueBuiltinAction的第一个参数作为新建action携带cmd的执行函数;
第二个参数既作为action的trigger name,也作为action携带cmd的参数。
void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name)
//创建action
auto action = std::make_unique<Action>(true);
std::vector<std::string> name_vectorname;
//保证trigger name的唯一性
if (!action->InitSingleTrigger(name))
return;
//创建action的cmd,指定执行函数和参数
action->AddCommand(func, name_vector);
trigger_queue_.push(std::make_unique<BuiltinTrigger>(action.get()));
actions_.emplace_back(std::move(action));
从上面的代码可以看出:
QueueBuiltinAction函数中将构造新的action加入到actions_链表中,
并将trigger事件加入到trigger_queue_中。
4.2、QueueEventTrigger
void ActionManager::QueueEventTrigger(const std::string& trigger)
trigger_queue_.push(std::make_unique<EventTrigger>(trigger));
此处QueueEventTrigger函数就是利用参数构造EventTrigger,然后加入到trigger_queue_中。
后续init进程处理trigger事件时,将会触发相应的操作。
五、处理添加到运行队列的事件
前面的代码已经将Action、Service、Trigger等加入到数据结构中了。
最后就到了处理这些数据的时候了:
..............
while (true)
// By default, sleep until something happens.
int epoll_timeout_ms = -1;
//当前没有事件需要处理时
if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec()))
//依次执行每个action中携带command对应的执行函数
am.ExecuteOneCommand();
if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec()))
//重启一些挂掉的进程
restart_processes();
// If there's a process that needs restarting, wake up in time for that.
if (process_needs_restart_at != 0)
决定timeout的时间,将影响while循环的间隔
epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
// If there's more work to do, wake up again immediately.
// 有command等着处理的话,不等待
if (am.HasMoreCommands()) epoll_timeout_ms = 0;
epoll_event ev;
//没有事件到来的话,最多阻塞epoll_timeout_ms时间
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
if (nr == -1)
PLOG(ERROR) << "epoll_wait failed";
else if (nr == 1)
//有事件到来,执行对应处理函数
//根据上文知道,epoll句柄(即epoll_fd)主要监听子进程结束,及其它进程设置系统属性的请求。
((void (*)()) ev.data.ptr)();
.....................
从上面代码可以看出,最终init进程将进入无限循环中,
不断处理运行队列中的事件、完成重启进程、监听epoll_fd等操作。
接下来,我们关注一下其中比较关键的函数ExecuteOneCommand和restart_processes。
5.1、ExecuteOneCommand
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();
//上面的代码说明,执行的顺序又trigger queue决定
//没有可执行的action时,直接退出
if (current_executing_actions_.empty())
return;
//每次只执行一个action,下次init进程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
//current_command_记录当前command对应的编号
//实际上就是执行该command对应的处理函数
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<Action>& a)
return a.get() == action;
;
actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));
从代码可以看出,当while循环不断调用ExecuteOneCommand函数时,将按照trigger表的顺序,
依次取出action链表中与trigger匹配的action。
每次均仅仅执行一个action中的一个command对应函数(一个action可能携带多个command)。
当一个action所有的command均执行完毕后,再执行下一个action。
当一个trigger对应的action均执行完毕后,再执行下一个trigger对应action。
5.2、restart_processes
restart_processes函数负责按需重启进程,代码如下图所示:
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。
我们进一步看看RestartIfNeeded函数:
void Service::RestartIfNeeded(time_t* process_needs_restart_at)
boot_clock::time_point now = boot_clock::now();
boot_clock::time_point next_start = time_started_ + 5s;
//两次服务启动进程的间隔要大于5s
if (now > next_start)
flags_ &= (~SVC_RESTARTING);
//满足时间间隔的要求后,重启进程
//Start将会重新fork服务进程,并做相应的配置
Start();
return;
//更新process_needs_restart_at的值,将影响前文epoll_wait的等待时间
time_t next_start_time_t = time(nullptr) +
time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count());
if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0)
*process_needs_restart_at = next_start_time_t;
六、结束
至此,init进程的启动流程分析完毕,
与Android 7.0相比,这部分流程的变化不是很大。
以上是关于Android O: init进程启动流程分析(阶段三)的主要内容,如果未能解决你的问题,请参考以下文章