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最后一个阶段:循环监听处理事件。