




已阅读5页,还剩7页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android系统启动流程(一)解析init进程前言作为“Android框架层”这个大系列中的第一个系列,我们首先要了解的是Android系统启动流程,在这个流程中会涉及到很多重要的知识点,这个系列我们就来一一讲解它们,这一篇我们就来学习init进程。1.init简介init进程是Android系统中用户空间的第一个进程,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建zygote(孵化器)和属性服务等。init进程是由多个源文件共同组成的,这些文件位于源码目录system/core/init。本文将基于Android7.0源码来分析Init进程。2.引入init进程说到init进程,首先要提到Android系统启动流程的前几步: 1.启动电源以及系统启动 当电源按下时引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序Bootloader到RAM,然后执行。 2.引导程序Bootloader 引导程序是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。 3.Linux内核启动 内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。 4.init进程启动讲到第四步就发现我们这一节要讲的init进程了。关于Android系统启动流程的所有步骤会在本系列的最后一篇做讲解。3.init入口函数init的入口函数为main,代码如下所示。 system/core/init/init.cppint main(int argc, char* argv) if (!strcmp(basename(argv0), ueventd) return ueventd_main(argc, argv); if (!strcmp(basename(argv0), watchdogd) return watchdogd_main(argc, argv); umask(0); add_environment(PATH, _PATH_DEFPATH); bool is_first_stage = (argc = 1) | (strcmp(argv1, -second-stage) != 0); /创建文件并挂载 if (is_first_stage) mount(tmpfs, /dev, tmpfs, MS_NOSUID, mode=0755); mkdir(/dev/pts, 0755); mkdir(/dev/socket, 0755); mount(devpts, /dev/pts, devpts, 0, NULL); #define MAKE_STR(x) _STRING(x) mount(proc, /proc, proc, 0, hidepid=2,gid= MAKE_STR(AID_READPROC); mount(sysfs, /sys, sysfs, 0, NULL); open_devnull_stdio(); klog_init(); klog_set_level(KLOG_NOTICE_LEVEL); NOTICE(init %s started!n, is_first_stage ? first stage : second stage); if (!is_first_stage) / Indicate that booting is in progress to background fw loaders, etc. close(open(/dev/.booting, O_WRONLY | O_CREAT | O_CLOEXEC, 0000); /初始化属性相关资源 property_init();/1 process_kernel_dt(); process_kernel_cmdline(); export_kernel_boot_props(); . /启动属性服务 start_property_service();/2 const BuiltinFunctionMap function_map; Action:set_function_map(&function_map); Parser& parser = Parser:GetInstance(); parser.AddSectionParser(service,std:make_unique(); parser.AddSectionParser(on, std:make_unique(); parser.AddSectionParser(import, std:make_unique(); /解析init.rc配置文件 parser.ParseConfig(/init.rc);/3 . while (true) if (!waiting_for_exec) am.ExecuteOneCommand(); restart_processes(); int timeout = -1; if (process_needs_restart) timeout = (process_needs_restart - gettime() * 1000; if (timeout 0) timeout = 0; if (am.HasMoreCommands() timeout = 0; bootchart_sample(&timeout); epoll_event ev; int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout); if (nr = -1) ERROR(epoll_wait failed: %sn, strerror(errno); else if (nr = 1) (void (*)() ev.data.ptr)(); return 0;init的main方法做了很多事情,我们只需要关注主要的几点,在注释1处调用 property_init来对属性进行初始化并在注释2处的 调用start_property_service启动属性服务,关于属性服务,后面会讲到。注释3处 parser.ParseConfig(“/init.rc”)用来解析init.rc。解析init.rc的文件为system/core/init/init_parse.cpp文件,接下来我们查看init.rc里做了什么。4.init.rcinit.rc是一个配置文件,内部由Android初始化语言编写(Android Init Language)编写的脚本,它主要包含五种类型语句: Action、Commands、Services、Options和Import。init.rc的配置代码如下所示。 system/core/rootdir/init.rcon init sysclktz 0 # Mix device-specific information into the entropy pool copy /proc/cmdline /dev/urandom copy /p /dev/urandom.on boot # basic network init ifup lo hostname localhost domainname localdomain # set RLIMIT_NICE to allow priorities from 19 to -20 setrlimit 13 40 40. 这里只截取了一部分代码,其中#是注释符号。on init和on boot是Action类型语句,它的格式为:on & * /设置触发器 /动作触发之后要执行的命令 为了分析如何创建zygote,我们主要查看Services类型语句,它的格式如下所示:service * / /option是service的修饰词,影响什么时候、如何启动services . 需要注意的是在Android 7.0中对init.rc文件进行了拆分,每个服务一个rc文件。我们要分析的zygote服务的启动脚本则在init.zygoteXX.rc中定义,这里拿64位处理器为例,init.zygote64.rc的代码如下所示。 system/core/rootdir/init.zygote64.rcservice zygote /system/bin/app_process64 -Xzygote /system/bin -zygote -start-system-server class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart netdwritepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks其中service用于通知init进程创建名zygote的进程,这个zygote进程执行程序的路径为/system/bin/app_process64,后面的则是要传给app_process64的参数。class main指的是zygote的class name为main,后文会用到它。5.解析service接下来我们来解析service,会用到两个函数,一个是ParseSection,它会解析service的rc文件,比如上文讲到的init.zygote64.rc,ParseSection函数主要用来搭建service的架子。另一个是ParseLineSection,用于解析子项。代码如下所示。 system/core/init/service.cppbool ServiceParser:ParseSection(const std:vector& args, std:string* err) if (args.size() 3) *err = services must have a name and a program; return false; const std:string& name = args1; if (!IsValidName(name) *err = StringPrintf(invalid service name %s, name.c_str(); return false; std:vector str_args(args.begin() + 2, args.end(); service_ = std:make_unique(name, default, str_args);/1 return true;bool ServiceParser:ParseLineSection(const std:vector& args, const std:string& filename, int line, std:string* err) const return service_ ? service_-HandleLine(args, err) : false;注释1处,根据参数,构造出一个service对象,它的classname为”default”。当解析完毕时会调用EndSection:void ServiceParser:EndSection() if (service_) ServiceManager:GetInstance().AddService(std:move(service_); 接着查看AddService做了什么: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; services_.emplace_back(std:move(service);/1注释1处的代码将service对象加入到services链表中。上面的解析过程总体来讲就是根据参数创建出service对象,然后根据选项域的内容填充service对象,最后将service对象加入到vector类型的services链表中。,6.init启动zygote讲完了解析service,接下来该讲init是如何启动service,在这里我们主要讲解启动zygote这个service。在zygote的启动脚本中我们得知zygote的class name为main。在init.rc有如下配置代码: system/core/rootdir/init.rc.on nonencrypted # A/B update verifier that marks a successful boot. exec - root - /system/bin/update_verifier nonencrypted class_start main class_start late_start . 其中class_start是一个COMMAND,对应的函数为do_class_start。我们知道main指的就是zygote,因此class_start main用来启动zygote。do_class_start函数在builtins.cpp中定义,如下所示。system/core/init/builtins.cppstatic int do_class_start(const std:vector& args) /* Starting a class does not start services * which are explicitly disabled. They must * be started individually. */ ServiceManager:GetInstance(). ForEachServiceInClass(args1, (Service* s) s-StartIfNotDisabled(); ); return 0;来查看StartIfNotDisabled做了什么: system/core/init/service.cppbool Service:StartIfNotDisabled() if (!(flags_ & SVC_DISABLED) return Start(); else flags_ |= SVC_DISABLED_START; return true;接着查看Start方法,如下所示。bool Service:Start() flags_ &= (SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START); time_started_ = 0; if (flags_ & SVC_RUNNING) /如果Service已经运行,则不启动 return false; bool needs_console = (flags_ & SVC_CONSOLE); if (needs_console & !have_console) ERROR(service %s requires consolen, name_.c_str(); flags_ |= SVC_DISABLED; return false; /判断需要启动的Service的对应的执行文件是否存在,不存在则不启动该Service struct stat sb; if (stat(args_0.c_str(), &sb) = -1) ERROR(cannot find %s (%s), disabling %sn, args_0.c_str(), strerror(errno), name_.c_str(); flags_ |= SVC_DISABLED; return false; . pid_t pid = fork();/1.fork函数创建子进程 if (pid = 0) /运行在子进程中 umask(077); for (const auto& ei : envvars_) add_environment(.c_str(), ei.value.c_str(); for (const auto& si : sockets_) int socket_type = (si.type = stream ? SOCK_STREAM : (si.type = dgram ? SOCK_DGRAM : SOCK_SEQPACKET); const char* socketcon = !si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str(); int s = create_socket(.c_str(), socket_type, si.perm, si.uid, si.gid, socketcon); if (s = 0) PublishSocket(, s); . /2.通过execve执行程序 if (execve(args_0.c_str(), (char*) &strs0, (char*) ENV) = PROP_VALUE_MAX) return -1; if (strcmp(selinux.reload_policy, name) = 0 & strcmp(1, value) = 0) if (selinux_reload_policy() != 0) ERROR(Failed to reload policyn); else if (strcmp(selinux.restorecon_recursive, name) = 0 & valuelen 0) if (restorecon_recursive(lue) != 0) ERROR(Failed to restorecon_recursive %sn, value); /从属性存储空间查找该属性 prop_info* pi = (prop_info*) _system_property_find(name); /如果属性存在 if(pi != 0) /如果属性以ro.开头,则表示是只读,不能修改,直接返回 i
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 应急安全技能培训内容课件
- 新解读《DL-T 698.41-2010电能信息采集与管理系统 第4-1部分:通信协议-主站与电能信息采集终端通信》
- 2025年内蒙古巴彦淖尔市蒙医医院招聘3人笔试高频难、易错点备考题库及参考答案详解1套
- 应急专家培训课件
- 2025重庆市渝中区大坪街道社区卫生服务中心招聘2人笔试备考题库及答案详解(新)
- 2025年山东济南市章丘区所属事业单位招聘初级综合类岗位31人笔试备考题库及完整答案详解1套
- 癌症预警信号与自我检查
- 艾灸在秋季腹泻恢复期调理中适用范围
- 管水库合同(标准版)
- 计量水费合同(标准版)
- 2025年税收和注册税务师知识竞赛题目及答案
- 2025年工会经审财务知识竞赛培训试题考试题库(含答案)
- Starter Unit2 Keep TidySectionB(1a-1d)公开课一等奖创新教学设计人教版(2024)七年级英语上册
- 2025湖南衡阳工会招聘11名工会社会工作者备考考试题库附答案解析
- 焊接质量检测记录规范模板
- 2025年辽宁省交通建设投资集团招聘(104人)备考练习试题及答案解析
- 七年级上册数学《相交线与平行线》100题练习(含答案)
- 西藏文化考试题目及答案
- 重庆市南开中学高2026届高三第一次质量检测+英语答案
- 2025秋外研新版三起点小学英语四年级上册教学计划
- 2025北师大版(2024)三年级上册数学教学计划
评论
0/150
提交评论