静态的程序代码和程序运行时的状态,有很大的不同。理解代码,要理解其运行时的样子。
这一篇主要说说 android property service 的运行时状态。
先来看看这个图大致理解一下:
可以查看下手机的 /dev/__properties__ 文件(Kitkat 4.4) :
1 2 |
|
Init 进程,创建 /dev/__properties__ 文件,map 到内存,然后从 /default.prop等文件中加载 properties, 写入 /dev/__properties__. 然后启动 property_service , 就是建立一个 property_service
的 socket ,监听这个 socket ,其他进程通过向这个 socket 发送 proper_set 的消息来完成 properties 的设置。
proper_get 是在每个进程在初始化时(libc中) 建立了 /dev/__properties__到内存的 map ,得到了可以直接访问的 address,可以直接遍历 properties 的存储空间完成查找.
下面细细到来:
Init 进程,Android 用户空间的第一个进程,内核启动之后会执行这个 init 程序。进入到 init 的main 函数。 在 init.c 的 main 函数里面,初始化 property 相关的存储空间。
system/core/init/init.c
1
|
|
property_init
是调用 property_service.c 的方法。
/system/core/init/property_service.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
__system_property_area_init
方法在 bionic/libc/bionic/system_properties.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
|
首先创建 /dev/__properties__ ,并且用 mmap
映射到内存.(通过变量__system_property_area__
的共享,完成 property_service 和 libc 中 properties 相关的交互。)
1 2 3 4 5 6 7 8 9 10 |
|
回到 init.c , 加载 boot defults properties:
init.c
1
|
|
property_service.c:
1 2 3 4 5 6 |
|
load_properties_from_file
这个里面就是读取文件,然后 set_property
。
回到 init.c , 启动 property service :
init.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
在 start_property_service
中,加载 properties (/system/build.prop, /system/default.prop, /data/property/xxx),创建 /dev/socket/property_service 这个 socket, 并且监听这个 socket 来接受 set property 的消息。
property_service.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
回到 init.c :
init 进程在 main 函数的最后,进入一个无限循环,等待 /dev/socket/property_service 和其他 fd 的事件并处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
|
handler_property_set_fd
里面接收 /dev/socket/property_service
的消息并处理。
property_service.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
|
在 property_set
之前会 check_perms
, 不同的 property_set 需要什么权限呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
接着就 property_set
:
先查询有的话,就 __system_property_update
, 没有就 __system_property_add
,如果是 persist.
的话,要 write_persistent_property
写入到 /data/property/xxx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
|
OK, proper_set
流程先到这里,下面来看看 proper_get
. proper_get
直接向下到 libc 的 __system_property_get
的 api.
/bionic/libc/bionic/system_properties.c
1 2 3 4 5 6 7 8 9 10 11 |
|
这里是调用了 __system_property_find
来查找这个值。在往下看:
1 2 3 4 5 6 7 |
|
这里调用 find_property
来访问 root_node()
, 什么是 root_node()
?
1 2 3 4 5 6 7 8 9 10 11 12 |
|
实际上获取 __system_property_area__->data
的地址开始访问。OK, __system_property_area__
是哪里? 正是 /dev/properties map 到内存的地址。
init.c 进程调用了 system_properties.c 的 __system_property_area_init
–> map_prop_area_rw
在这里:
创建 property_filename
(/dev/_-properties__), mmap
到内存, 将地址赋值给 __system_property_area__
。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
但是,慢着! 这些都是在 init 进程里面执行的,其他进程调用 __system_property_find
怎么可以直接访问 __system_property_area__
? 难道 其他进程和 init 共享了这个地址,这是不可能的,这个变量怎会传递到 init 的子进程?就算传递了,它们怎么可能访问相同的地址呢?它们可是不同进程啊,各自使用自己独享的内存空间啊!
所以,呵呵! 其他进程肯定也对 __system_property_area__
进行初始化了! 在哪里 ?
/bionic/libc/bionic/libc_init_common.cpp 中 调用了 __system_properties_init()
1 2 3 4 |
|
/bionic/libc/bionic/system_properties.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
以 RDONLY 模式打开了 /dev/__properties__
文件,并且 mmap 到内存,将地址赋值给 __system_property_area__
! 所以,其他进程可以直接访问 __system_property_area__
不过这个肯定和 init 进程里那个是不同的!!
OK! 结束,下一篇讲讲 property 存储区的数据结构 !