在使用Android的属性系统(property system)时遇到了一些问题,结合此次经历,对属性系统的使用做以简单介绍。
一、Property系统简介
属性系统是android的一个重要特性。它作为一个服务运行,管理系统配置和状态。所有这些配置和状态都是属性。每个属性是一个键值对(key/value pair),其类型都是字符串。
从功能上看,属性与windows系统的注册表非常相似。许多android应用程序和库直接或者间接地依赖此特性,以决定它们的运行时行为。例如,adbd进程查询属性服务已确认当前是否运行在模拟器环境中。另一个例子是java.io.File.pathSpearator,其返回存储于属性服务中的值。
二、Property系统使用
使用property系统,首先需要包含头文件<cutils/properties.h>,同时需要在Android.mk文件中加入库libcutils。
具体的使用实例如下:
property_set("hw.jpeg.path", "/data/test.jpg");
char propBuf[PROPERTY_VALUE_MAX];
property_get("hw.jpeg.path ", propBuf, "");
LOGI("property_get: %s.", propBuf);
Property系统的使用很简单,这里需要说明的,只有一个问题,那就是属性名称。
三、Property系统的属性名称
Property系统中使用的属性名称有一定的命名规则。
如果属性名称以“ro.”开头,那么这个属性被视为只读属性。一旦设置,属性值不能改变。
如果属性名称以“persist.”开头,当设置这个属性时,其值也将写入/data/property。
如果属性名称以“net.”开头,当设置这个属性时,“net.change”属性将会自动设置,以加入到最后修改的属性名。(这是很巧妙的。 netresolve模块的使用这个属性来追踪在net.*属性上的任何变化。)
属性“ ctrl.start ”和“ ctrl.stop ”是用来启动和停止服务。每一项服务必须在/init.rc中定义.系统启动时,与init守护进程将解析init.rc和启动属性服务。一旦收到设置“ ctrl.start ”属性的请求,属性服务将使用该属性值作为服务名找到该服务,启动该服务。这项服务的启动结果将会放入“ init.svc.<服务名>“属性中 。客户端应用程序可以轮询那个属性值,以确定结果。
另外,还有其他的前缀;在介绍这些前缀之前,我们先来看点别的东西。
在文件system/core/init/property_service.h中,有如下两个函数定义:
extern void handle_property_set_fd(int fd);
extern int property_set(const char *name, const char *value);
它们的实现都位于system/core/init/property_service.c。
另外在system/core/init/init.c中,有如下code:
int main(int argc, char **argv)
{
……
for(;;) {
……
if (ufds[0].revents == POLLIN)
handle_device_fd(device_fd);
if (ufds[1].revents == POLLIN)
handle_property_set_fd(property_set_fd);
if (ufds[3].revents == POLLIN)
handle_keychord(keychord_fd);
}
……
}
在开机启动后的init操作中,会执行一个loop循环,当检测到有新的设置时,进入设置流程,鉴权失败会提示相关的异常,如:
sys_prop: permission denied uid:1013 name:hw.jpeg.path
这里得介绍一下函数handle_property_set_fd(),其实现为:
void handle_property_set_fd(int fd)
{
prop_msg msg;
……
switch(msg.cmd) {
case PROP_MSG_SETPROP:
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
if(memcmp(msg.name,"ctl.",4) == 0) {
if (check_control_perms(msg.value, cr.uid, cr.gid)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);
} else {
ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d/n",
msg.name + 4, msg.value, cr.uid, cr.pid);
}
} else {
if (check_perms(msg.name, cr.uid, cr.gid)) {
property_set((char*) msg.name, (char*) msg.value);
} else {
ERROR("sys_prop: permission denied uid:%d name:%s/n",
cr.uid, msg.name);
}
}
break;
default:
break;
}
}