前文已经介绍完init进程第一阶段的初始化,接下来我们开始讲解init进程第二阶段初始化过程,首先是属性的设置。
如代码3-10所示,第二阶段一开始,即在“/dev”目录下创建“.booting”文件,以通知其它进程当前正处于启动过程。
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
代码 3-10 创建“/dev/.booting”
在Android系统中,属性是一种特殊的资源,Android系统通过属性暴露设备和运行时信息,应用程序通过读写属性能够获得相应的信息,以及控制系统的行为,如代码3-11所示是属性的初始化。
property_init();[1]
代码 3-11 main()-属性内存区域初始化
在Android系统中,所有进程共享系统设置值,为此提供了一块属性内存区域。init进程调用代码3-12所示的property_init()函数,创建并初始化该内存区域。具体实现是property_init()函数通过调用__system_property_area_init()[2]函数完成。
首先,__system_property_area_init()函数在顶级目录下创建 “/dev/__properties__”子目录,用于保存属性的上下文文件。而后打开“/property_contexts”[3]文件,遍历其中的属性前缀及控制访问权限的上下文,将它们加载到内存中的链表。随后将链表中的每一个上下文在“/dev/__properties__”目录中都创建一个同名的文件,其中保存着受其控制的属性。最后把“/dev/__properties__”中的上下文文件映射到共享内存中,实现对属性的权限控制。
系统中其它进程通过执行中的进程所提供的API访问属性域中的设置值,但更改属性值仅能在init进程中进行。当修改属性值时,要预先向init进程提交值变更请求,然后init进程处理该请求,并修改属性值。
代码3-12将属性初始化到内存中。
process_kernel_dt(); (1)
process_kernel_cmdline(); (2)
export_kernel_boot_props(); (3)
代码 3-12 main()-属性初始化
(1)初始化DT(Device Tree)的属性集,即访问“/proc/device-tree/firmware/android ”目录,先看compatible文件内容是否是“android,firmware”,然后这个目录下每个文件名作为属性,文件里面的内容作为属性值。
(2)处理内核命令行,读取“/proc/cmdline”文件中的内容,然后调用import_kernel_nv()函数设置系统属性,此处只将“/proc/cmdline”中前缀为“androidboot.”的值设置到属性中。1中设置的DT属性集优先级高于此处设置的属性。
(3)设置内核启动的变量,根据系统已有的属性设置,如有值则保持不变,否则设置成初始值。
上述步骤基本就将Android系统所需的属性初始化好。正如前面我们介绍的,init进程是其它所有进程的父进程,它需要监视和处理子进程的终止,为此需要初始化信号处理器,下一篇我们将介绍这方面的内容。
[1] property_init()函数在system/core/init/property_service.cpp中定义。
[2] __system_property_area_init()函数在bionic/libc/bionic/system_properties.cpp中定义。
[3] property_contexts文件定义在system/sepolicy/property_contexts。