Android启动源码阅读(一)init进程的启动
在Linux系统中,Kernel启动完毕之后,启动的第一个用户空间的进程,就是名为init的进程:
以下是查找init进程源码的过程:
查找init进程mk文件位置:
查找可执行程序:init的编译MODULE定义,即全局查找字符串: LOCAL_MODULE:= init,从而找到mk文件位置system/core/init/Android.mk
从MODULE的LOCAL_SRC_FILES找到init.cpp文件
全局查找文件(按两次)init.cpp,从而最终找到init.cpp的源码system/core/init/init.cpp
init启动解析: main函数
作为init可执行文件的入口init.cpp->main(),我们来看下它是怎么执行的
总结下来,init进程做了几件事情:
- bin环境变量的添加
- 所需的文件系统的挂载
- 信号处理、oem锁、属性服务启动
- init.rc文件的解析
- 进入循环,通过ActionManager开始执行Command
- restart_processes,重新启动process,如果有必要的话
本文,我们只关注两点:
- rc文件的解析
- restart_processes 启动新的process
init.rc文件的解析过程
init.rc文件位于system/core/rootdir/init.rc
rc文件的变化
在 7.+ 版本的系统中,rc文件的内容根据具体的模块拆分成不同的rc文件,
比如init.rc文件的头部:
又比如servicemanager的初始化: frameworks/native/cmds/servicemanager/servicemanager.rc
参考链接:http://blog.csdn.net/sunao2002002/article/details/52454878
解析源码段分析
先来看看代码段
Parser是一个单例,全局字符串查找 Parser::GetInstance,即可找到定义位置system/core/init/init_parser.cpp
1234Parser& Parser::GetInstance() {static Parser instance;return instance;}调用AddSectionParser将几个解析器放置到map中:
1234void Parser::AddSectionParser(const std::string& name,std::unique_ptr<SectionParser> parser) {section_parsers_[name] = std::move(parser);}开始解析:
parser.ParseConfig("/init.rc");
123456bool Parser::ParseConfig(const std::string& path) {if (is_dir(path.c_str())) {return ParseConfigDir(path);}return ParseConfigFile(path);}
由于传入的”/init.rc”是一个文件,因此开始ParseConfigFile(path)
解析
- file解析123456789101112131415161718192021222324bool Parser::ParseConfigFile(const std::string& path) {INFO("Parsing file %s...\n", path.c_str());Timer t;std::string data;//将file内容读入data字符串中if (!read_file(path.c_str(), &data)) {return false;}//内容字符串修正data.push_back('\n'); // TODO: fix parse_config.//4.1 解析文件内容ParseData(path, data);for (const auto& sp : section_parsers_) {//4.2 解析文件完毕sp.second->EndFile(path);}// Turning this on and letting the INFO logging be discarded adds 0.2s to// Nexus 9 boot time, so it's disabled by default.if (false) DumpState();NOTICE("(Parsing %s took %.2fs.)\n", path.c_str(), t.duration());return true;}
ParseData()解析说明
|
|
GetInstance
举例说明解析过程
- 读取init.rc文件时,遇到import语句,因此args[0] = “import”,采用ImportParser进行解析
调用ImportParser->ParseSection进行解析:args={“import”, “/init.${ro.zygote}.rc”}
1234567891011121314151617181920bool ImportParser::ParseSection(const std::vector<std::string>& args,std::string* err) {if (args.size() != 2) {*err = "single argument needed for import\n";return false;}std::string conf_file;//通过expand_props将${ro.zygote}替换成对应平台的实现,例如zygote32,因此文件名为:init.zygote32.rcbool ret = expand_props(args[1], &conf_file);if (!ret) {*err = "error while expanding import";return false;}INFO("Added '%s' to import list\n", conf_file.c_str());//将解析出来,import的真正文件名放到imports_列表中imports_.emplace_back(std::move(conf_file));return true;}回到Parser::ParseConfigFile,当文件解析完毕之后,调用所有的Parser->EndFile
1234for (const auto& sp : section_parsers_) {//4.2 解析文件完毕sp.second->EndFile(path);}
因此,我们看下ImportParser->EndFile():
由此可见,又针对每个文件,进行了Parser::GetInstance().ParseConfig(s)解析
imprt进来的file的解析步骤仍然走的:
- Parser::ParseConfig
- Parser::ParseConfigFile
- 循环1. Parser::ParseData
- 循环2. system/core/init/parser.cpp->next_token()
- 循环3. Parser::ParseSection
- 循环4. Parser::EndSection
我们来看service的解析:
12345678910service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-serverclass mainsocket zygote stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdwritepid /dev/cpuset/foreground/tasks- 在ParserData()的时候,args[0]=”service”,采用ServiceParser进行解析1234567891011121314151617bool ServiceParser::ParseSection(const std::vector<std::string>& args,std::string* err) {if (args.size() < 3) {*err = "services must have a name and a program";return false;}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_ = std::make_unique<Service>(name, "default", str_args);return true;}
由此可见,service关键字的解析,将会创建Service对象,并赋值给ServiceParser的service_成员
- 当这一行解析完毕之后,进入下一行,由于下一行的args[0]不为{“service”,”on”,”import”}中的任意一个,因此进入解析方法ParseLineSection 123bool ServiceParser::ParseLineSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) const {return service_ ? service_->HandleLine(args, err) : false;}
HandleLine方法
12345678910111213141516bool Service::HandleLine(const std::vector<std::string>& args, std::string* err) {if (args.empty()) {*err = "option needed, but not provided";return false;}//根据OptionHandlerMap,找寻args[0]所对应的函数static const OptionHandlerMap handler_map;auto handler = handler_map.FindFunction(args[0], args.size() - 1, err);if (!handler) {return false;}//找到args[0]对应的方法,调用该方法,并将方法的返回值true/false,//返回: 这些方法基本上都是service_的属性设置,返回的都是boolean值return (this->*handler)(args, err);}//OptionHandlerMap定义如下
1234567891011121314151617181920Service::OptionHandlerMap::Map& Service::OptionHandlerMap::map() const {constexpr std::size_t kMax = std::numeric_limits<std::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;}- 当所有的Line解析完毕,到达文件末尾,则调用ServiceParser::EndSection方法:12345void ServiceParser::EndSection() {if (service_) {ServiceManager::GetInstance().AddService(std::move(service_));}}
将刚才解析的service_成员,move到ServiceManager的列表中
123456789void ServiceManager::AddService(std::unique_ptr<Service> service) {Service* old_service = FindServiceByName(service->name());if (old_service) {ERROR("ignored duplicate definition of service '%s'",service->name().c_str());return;}services_.emplace_back(std::move(service));}- 至此,init.zygote32.rc文件解析完毕
- 在ParserData()的时候,args[0]=”service”,采用ServiceParser进行解析
restart_processes
前面分析init.cpp->main()函数的时候,在while循环中,调用了restart_processes方法
|
|
从代码看到,这段代码对每一个Service,都进行了调用函数调用
因此,最终调用到了
|
|
调用到了Service:Start()方法: system/core/init/service.cpp
这段代码比较长,就不贴了,列举几个重要的片段:
fork一个新的进程
1pid_t pid = fork();在新的进程中,如果sockets_不为空,就创建socket: 此处init.zygote32.rc文件中,socket zygote stream 660 root system
|
|
因此会创建一个名为zygote的socket,挂在在/dev/socket/zygote节点下,
最终通过execve来执行 /system/bin/app_process
至此,一个service进程就解析,并创建进程,在新进程中开始执行
完结
上述分析,仅仅针对service关键字做了分析,其他的关键字on、class等等,同理分析
参考资料: