分类: LINUX
2012-04-10 17:03:53
在使用Android的属性系统(property system)时遇到了一些问题,结合此次经历,对属性系统的使用做以简单介绍。
一、Property系统简介
属性系统是android的一个重要特性。它作为一个服务运行,管理系统配置和状态。所有这些配置和状态都是属性。每个属性是一个键值对(key/value pair),其类型都是字符串。
从功能上看,属性与windows系统的注册表非常相似。许多android应用程序和库直接或者间接地依赖此特性,以决定它们的运行时行为。例如,adbd进程查询property服务已确认当前是否运行在模拟器环境中。另一个例子是java.io.File.pathSpearator,其返回存储于property服务中的值。
二、Property系统使用
使用property系统,首先需要包含头文件
具体的使用实例如下:
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和启动property服务。一旦收到设置“ ctrl.start ”属性的请求,property服务将使用该属性值作为服务名找到该服务,启动该服务。这项服务的启动结果将会放入“ 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;
}
}
其中check_perms()的实现如下:
static int check_perms(const char *name, unsigned int uid, int gid)
{
int i;
if (uid == 0)
return 1;
if(!strncmp(name, "ro.", 3))
name +=3;
for (i = 0; property_perms[i].prefix; i++) {
int tmp;
if (strncmp(property_perms[i].prefix, name,
strlen(property_perms[i].prefix)) == 0) {
if ((uid && property_perms[i].uid == uid) ||
(gid && property_perms[i].gid == gid)) {
return 1;
}
}
}
return 0;
}
通过这两个函数,我们可以知道,我们所设置的属性名称hw.jpeg.path会与结构体property_perms中的前缀做比较,如果满足,则又会比较uid。
结构体property_perms的定义如下:
struct {
const char *prefix;
unsigned int uid;
unsigned int gid;
} property_perms[] = {
{ "net.rmnet0.", AID_RADIO, 0 },
{ "net.gprs.", AID_RADIO, 0 },
{ "net.ppp", AID_RADIO, 0 },
{ "ril.", AID_RADIO, 0 },
{ "gsm.", AID_RADIO, 0 },
{ "persist.radio", AID_RADIO, 0 },
{ "net.dns", AID_RADIO, 0 },
{ "net.", AID_SYSTEM, 0 },
{ "dev.", AID_SYSTEM, 0 },
{ "runtime.", AID_SYSTEM, 0 },
{ "hw.", AID_SYSTEM, 0 },
{ "sys.", AID_SYSTEM, 0 },
{ "service.", AID_SYSTEM, 0 },
{ "wlan.", AID_SYSTEM, 0 },
{ "dhcp.", AID_SYSTEM, 0 },
{ "dhcp.", AID_DHCP, 0 },
{ "vpn.", AID_SYSTEM, 0 },
原文地址:http://blog.chinaunix.net/uid-22935566-id-2602712.html