3.5.4 init对属性服务的处理
init中除了解析init.rc中配置的Action和Service外,还处理了一些内置Action,这些工作由queue_builtin_action函数完成。其中最重要的便是属性服务(Property Service)相关的部分。
1.处理属性服务的流程
Android为了存储全局系统设置信息,提供了一个系统属性共享内存区,这个共享内存区的内容是一些键值对的列表,对外提供get和set方法读写属性。系统启动时由init初始化并开启属性服务。现在回到init.c的main函数,分析init中是如何处理属性服务的。定位到属性服务相关部分,代码如下:
//共享内存区分配
property_init();
……
if(!is_charger)
//加载默认属性
property_load_boot_defaults();
……
//触发属性服务相关的Action
queue_builtin_action(property_service_init_action,"property_service_init");
queue_builtin_action(queue_property_triggers_action,"queue_propety_triggers");
init中与属性服务相关的工作有四部分:
1)通过property_init函数调用init_property_area()函数初始化属性区,打开ashmem设备,申请共享内存,以便所有用户进程可以共享这块内存。
2)通过property_load_boot_defaults函数加载/default.prop文件中定义的默认属性。
3)通过queue_builtin_action函数触发property_service_init。
4)通过queue_builtin_action函数触发queue_propety_triggers。
其中第一部分涉及Android Shared Memory,读者只需要知道分配了一块共享内存区域便可;第二部分只是简单的文件加载。下面只分析第三部分和第四部分。
(1)property_service_init_action
property_service_init_action是init执行的第一个属性触发函数,位于init.c中,在其内部直接调用了start_property_service函数,该函数定义于property_service.c中,代码如下:
void start_property_service(void)
{
int fd;
/*这里加载了其他默认属性文件
*#define PROP_PATH_SYSTEM_BUILD"/system/build.prop"
*#define PROP_PATH_SYSTEM_DEFAULT"/system/default.prop"
*#define PROP_PATH_LOCAL_OVERRIDE"/data/local.prop"
*/
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
ifdef ALLOW_LOCAL_PROP_OVERRIDE
load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
endif
/*默认属性加载完毕后,加载一些持久化的属性。存储持久化属性的路径位
*于/data/property目录下,由PERSISTENT_PROPERTY_DIR宏定义
*#define PERSISTENT_PROPERTY_DIR"/data/property"
持久化属性,是以persist.开头的属性/
load_persistent_properties();
/#define PROP_SERVICE_NAME"property_service"创建一个Socket,用于接收客户端请求/
fd=create_socket(PROP_SERVICE_NAME, SOCK_STREAM,0666,0,0);
if(fd<0)return;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
/*监听fd上的连接请求,并建立一个请求队列,最大请求数是8
这些连接请求将在请求队列中等待被accept()方法接收/
listen(fd,8);
/设置property_set_fd以便在init中处理。还记得init中poll函数在等待这个fd上的事件发生吗/
property_set_fd=fd;
}
start_property_service方法中主要做了三部分工作:1)加载属性文件,2)创建Socket接收客户端请求,3)监听Socket。
(2)queue_property_triggers_action
queue_property_triggers_action是init执行的第二个属性触发函数,位于init.c中,代码如下:
static int queue_property_triggers_action(int nargs, char**args)
{
queue_all_property_triggers();
property_triggers_enabled=1;//为property_triggers_enabled赋值
return 0;
}
这里调用了queue_all_property_triggers,位于init_parser.c中,代码如下:
void queue_all_property_triggers()
{
struct listnode*node;
struct action*act;
/遍历action_list/
list_for_each(node,&action_list){
/取出一个Action/
act=node_to_item(node, struct action, alist);
/判断Action名字中是否有property:,解析property:<name>=<value>/
if(!strncmp(act->name,"property:",strlen("property:"))){
const char*name=act->name+strlen("property:");
const char*equals=strchr(name,'=');
if(equals){
……//省略部分内容
if(length>PROP_NAME_MAX){//错误处理
}else{
……//省略部分内容
value=property_get(prop_name);
if(value&&(!strcmp(equals+1,value)||!strcmp(equals+1,"*"))){
//将这些Action加入可执行队列
action_add_queue_tail(act);
}
……//省略部分内容
}
queue_property_triggers_action触发了所有名字以"property:"开头的Action。Android的属性系统是一种特殊的Action,这种Action以"on property:"为前缀,其代码如下:
on property:ro.debuggable=1
start console
ro. debuggable=1定义了一个条件,只有当这个条件为真时,才执行Action中指定的Command。
2.属性服务客户端
前面分析到start_property_service中开启了一个Socket接收客户端请求,这个请求又是从哪里发出的?即属性服务的客户端是什么?
在属性设置过程中,属性服务器调用了property_set函数设置属性。其实在客户端也有一个对应的名为property_set的函数,这个函数供客户端与属性服务通信,位于/system/core/libcutils/properties.c,代码如下:
int property_set(const charkey, const charvalue)
{
return__system_property_set(key, value);
}
这里调用了__system_property_set函数,位于bionic/libc/bionic/system_properties.c中,代码如下:
int__system_property_set(const charkey, const charvalue)
{
int err;
int tries=0;
int update_seen=0;
prop_msg msg;
……//省略部分内容
/send_prop_msg中建立了s=socket(AF_LOCAL, SOCK_STREAM,0)/
err=send_prop_msg(&msg);
……//省略部分内容
return 0;
}
接着分析send_prop_msg,在这里真正创建了Socket通信连接。代码如下:
static int send_prop_msg(prop_msg*msg)
{
struct pollfd pollfds[1];
struct sockaddr_un addr;
socklen_t alen;
size_t namelen;
int s;
int r;
int result=-1;
/创建Socket/
s=socket(AF_LOCAL, SOCK_STREAM,0);
……//省略部分内容
memset(&addr,0,sizeof(addr));
namelen=strlen(property_service_socket);
/设置服务Socket/
strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path);
addr.sun_family=AF_LOCAL;
alen=namelen+offsetof(struct sockaddr_un, sun_path)+1;
/连接服务Socket/
if(TEMP_FAILURE_RETRY(connect(s,(struct sockaddr*)&addr, alen)<0)){
close(s);
return result;
}
/发送消息/
r=TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg),0));
if(r==sizeof(prop_msg)){
……//省略部分内容
}
close(s);
return result;
}
可见Android的属性系统是通过Socket实现客户端和服务端通信的,通信的接口是property_set和property_get这两个函数。
到这里为止,属性系统的三大部分分析完了。接下来分析init最后一个阶段:循环监听处理事件。