1 libc中的实现
首先在init进程启动的时候
property_init()->__system_property_area_init()->map_prop_area_rw()
以读写的形式打开/dev/__properties__ 这个文件
const int fd = open(property_filename,
O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
虽然这个文件是只读的,但是init进程运行在root用户下,还是为所欲为的,以可写的方式进行打开。
之后把文件大小截断为128k,以读写的方式映射到init进程的一块内存区域
void *const memory_area = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
之后这块区域就用来存放property属性。之后system在open一个只读属性的/dev/__properties__文件,用于fork出子进程的时候传递给子进程,以后子进程使用该打开的property文件读取属性值。具体函数参考
map_prop_area()函数,子进程获取到父进程传递过来的打开的属性文件描述符后采用共享映射该文件。之后其他人修改属性值,就可以通过内存映射反应给任何一个子进程。
那么自进程如何修改property的值呢? 系统里只有init进程负责修改属性值。
init进程在初始化完成property共享内存后,会创建一个unix域套接字,用于接收其他进程的修改属性请求。进程要想修改属性,只能通过请求init进程完成,这部分是封装在__system_property_set和__system_property_update函数里面的,对开发者透明。
那么我们再来看看/dev/__properties__ 文件是以什么格式存储数据的。
在libc的system_properties.cpp的头部注释部分有相关描述,数状的结构,linux内核里也进程使用该结构替代映射关系。
/*
* Properties are stored in a hybrid trie/binary tree structure.
* Each property's name is delimited at '.' characters, and the tokens are put
* into a trie structure. Siblings at each level of the trie are stored in a
* binary tree. For instance, "ro.secure"="1" could be stored as follows:
*
* +-----+ children +----+ children +--------+
* | |-------------->| ro |-------------->| secure |
* +-----+ +----+ +--------+
* / \ / |
* left / \ right left / | prop +===========+
* v v v +-------->| ro.secure |
* +-----+ +-----+ +-----+ +-----------+
* | net | | sys | | com | | 1 |
* +-----+ +-----+ +-----+ +===========+
*/
也就是说以.分割,包含子孩子和左右节点的树形结构.