鸟人的Android揭秘(14)——Init进程源代码分析(五)

      前一篇主要讲解了init进程如何创建套接字以处理子进程终止,接下来我们继续分析init进程启动属性服务,以及分析init.rc的过程。

      接下来init进程需要设置系统属性,如代码3-16所示。

property_load_boot_defaults();
export_oem_lock_status();

代码 3-16 main()-设置系统属性

      property_load_boot_defaults()函数实际上就是调用load_properties_from_file()[1]函数解析“/default.prop”配置文件,然后根据解析的结果设置系统属性。export_oem_lock_status()函数根据系统状态设置“ro.boot.flash.locked”属性。这部分代码较为简单,不深入分析。

      然后启动属性服务,它是init进程最主要的功能之一。init进程在共享内存区域中,创建并初始化属性域。其它进程可以访问属性域中的值,但更改属性值仅能在init进程中进行。其它进程修改属性值时,要预先向init进程提交属性值变更申请,然后init进程处理该申请并修改属性值。在访问和修改属性时,init进程都可以进行权限控制。

start_property_service();

代码 3-17 main()-启动属性服务

      如前所述,属性值的更改仅能在init进程中进行,为此init进程生成“/dev/socket/property_service”套接字,以接收其它进程提交的申请。

      接下来init进程开始解析init.rc文件并执行相关的命令。init.rc文件大致分为两大部分,一部分是以“on”关键字开头的动作列表(Action List),另一部分是以“service”关键字开头的服务列表(Service List)。动作列表用于创建所需目录,以及为某些特定文件指定权限,而服务列表用来记录init进程需要启动的一些子进程。此外,还有一个关键字“import”,用于导入另外一个.rc文件,解析生成动作列表和服务列表,这些列表会分别被添加到init.rc文件已生成的服务列表和动作列表中。

      代码3-18所示创建了init.rc所需的解析器(Parser),用于解析“service”、“on”、“import”等关键字开始的列表。

const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
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>());

代码 3-18 main()-创建init.rc解析器

      然后便开始解析init.rc文件。init.rc文件是在init进程启动后执行的启动脚本,文件中记录着init进程执行的功能。在Linux系统中,它被定义在根文件系统的“/etc/rc.d/”目录下,是启动时的可执行文件,在“/etc”目录下保存着设置环境变量的脚本。但在Android系统中,仅使用init.rc与init.{hardware}.rc两个文件,init.rc文件在Android系统运行过程中用于通用的环境设置及进程相关的定义,init.{hardware}.rc用于定义Android在不同平台下的特定进程和环境设置等。

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

代码 3-19 main()-解析init.rc文件

      ParseConfig()方法传入参数是“/init.rc”,解析运行时与init进程同在根目录下的init.rc[2]文件。ParseConfig()方法实质上是调用ParseData()方法进行解析。执行该方法,读取并分析init.rc文件后,生成服务列表与动作列表。相对以前的代码,在Android 7.0的代码中,init.rc文件的解析已经做了较好的封装,动作列表解析后保存在ActionManager[3]类的actions_向量中,类似的,服务列表保存到ServiceManager[4]类的services_向量中。

      init进程会依次执行“early-init,init,late-init”片段中的命令,如代码3-20所示,init进程利用参数构造EventTrigger,然后加入到trigger_queue_中,后续init进程处理trigger事件时,将会触发相应的操作。init进程在后续代码依次构造了“early-init”、“init”、“late-init”的事件触发器,代码仅以构造“early-init”触发器为例。

am.QueueEventTrigger("early-init");

代码 3-20 main()-向执行队列中添加命令

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

// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
am.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");

代码 3-21 main()-构造新的Action

      init进程在紧接着还会构造几个action,使用方法与上述代码非常类似,此处不再赘述。下一篇我们将讲解init进程如何处理上文构造出来的这些trigger、action和service。

 

[1] load_properties_from_file()函数定义在system/core/init/property_service.cpp。

[2] init.rc文件在编译前,定义在system/core/rootdir/init.rc中。

[3] ActionManager定义在system/core/init/action.h中。

[4] ServiceManager定义在system/core/init/service.h中。

转载于:https://my.oschina.net/u/660323/blog/829348

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值