无论是命令行,java层最后都是调用c层的接口来实现,property_set, property_get,property_list。
./system/core/libcutils/properties.c中有三种实现方式,在我们的平台中定义了HAVE_LIBC_SYSTEM_PROPERTIES,这里以HAVE_LIBC_SYSTEM_PROPERTIES为例。
./build/core/combo/include/arch/linux-arm/AndroidConfig.h:249:#define HAVE_LIBC_SYSTEM_PROPERTIES 1
property_get:
int property_get(const char *key, char *value, const char *default_value){
len = __system_property_get(key, value);
return len;
}
int __system_property_get(const char *name, char *value){
const prop_info *pi = __system_property_find(name); // 根据名字找到对应的prop_info
return __system_property_read(pi, 0, value); // 读取值
}
const prop_info *__system_property_find(const char *name){
return __system_property_find_compat(name);
}
int __system_property_read(const prop_info *pi, char *name, char *value){
return __system_property_read_compat(pi, name, value);
}
const prop_info *__system_property_find_compat(const char *name){
prop_area_compat *pa = (prop_area_compat *)__system_property_area__;
unsigned count = pa->count;
unsigned *toc = pa->toc;
unsigned len = strlen(name);
prop_info_compat *pi;
// 遍历__system_property_area__
while(count--) {
unsigned entry = *toc++;
if(TOC_NAME_LEN(entry) != len) continue; // 长度不同就不用比较
pi = TOC_TO_INFO(pa, entry);
if(memcmp(name, pi->name, len)) continue; // 继续比较名称是否相同
return (const prop_info *)pi;
}
return 0;
}
int __system_property_read_compat(const prop_info *_pi, char *name, char *value)
{
unsigned serial, len;
const prop_info_compat *pi = (const prop_info_compat *)_pi;
for(;;) {
serial = pi->serial;
while(SERIAL_DIRTY(serial)) {
__futex_wait((volatile void *)&pi->serial, serial, 0);
serial = pi->serial;
}
len = SERIAL_VALUE_LEN(serial);
memcpy(value, pi->value, len + 1);
if(serial == pi->serial) {
if(name != 0) {
strcpy(name, pi->name);
}
return len;
}
}
}
从全局变量__system_property_area__中查找
property_list:
int __system_property_foreach_compat(
void (*propfn)(const prop_info *pi, void *cookie),
void *cookie){
prop_area_compat *pa = (prop_area_compat *)__system_property_area__;
unsigned i;
for (i = 0; i < pa->count; i++) {
unsigned entry = pa->toc[i];
prop_info_compat *pi = TOC_TO_INFO(pa, entry);
propfn((const prop_info *)pi, cookie);
}
return 0;
}
共享内存只读权限,set走以下方式,通过socket发送命令设置属性。
property_set:int property_set(const char *key, const char *value){
return __system_property_set(key, value);
}
int __system_property_set(const char *key, const char *value)
{
int err;
prop_msg msg;
if(key == 0) return -1;
if(value == 0) value = "";
if(strlen(key) >= PROP_NAME_MAX) return -1;
if(strlen(value) >= PROP_VALUE_MAX) return -1;
memset(&msg, 0, sizeof msg);
msg.cmd = PROP_MSG_SETPROP; // 发送命令
strlcpy(msg.name, key, sizeof msg.name);
strlcpy(msg.value, value, sizeof msg.value);
err = send_prop_msg(&msg);
if(err < 0) {
return err;
}
return 0;
}
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;
s = socket(AF_LOCAL, SOCK_STREAM, 0); // property_service服务启动时创建的socket
// ...
}
init中监听处理:
init的main函数最后会进入一个循环:
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents & POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
else if (ufds[i].fd == get_keychord_fd())
handle_keychord();
else if (ufds[i].fd == get_signal_fd())
handle_signal();
}
}
处理property设置:
void handle_property_set_fd(){
switch(msg.cmd) {
case PROP_MSG_SETPROP: // msg.cmd = PROP_MSG_SETPROP;
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
if(memcmp(msg.name,"ctl.",4) == 0) { // 如果是ctl开头,则为守护进程服务命令控制方式
// Keep the old close-socket-early behavior when handling
// ctl.* properties.
close(s);
if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);
} else {
ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
}
} else { // 否则先检查权限,调用init中的property_set来设置属性值
if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) {
property_set((char*) msg.name, (char*) msg.value);
} else {
ERROR("sys_prop: permission denied uid:%d name:%s\n",
cr.uid, msg.name);
}
}
}
}
ctl.命令操作守护进程服务
ctl.start,ctl.stop,ctl.restart
init中设置属性:
int property_set(const char *name, const char *value){
pi = (prop_info*) __system_property_find(name); // 查找属性是否存在
if(pi != 0) {
/* ro.* properties may NEVER be modified once set */
if(!strncmp(name, "ro.", 3)) return -1; // ro.开头的属性不能被改变
__system_property_update(pi, value, valuelen); // 更新属性值
} else {
ret = __system_property_add(name, namelen, value, valuelen); // 添加新属性
}
/* If name starts with "net." treat as a DNS property. */
if (strncmp("net.", name, strlen("net.")) == 0) {
if (strcmp("net.change", name) == 0) {
return 0;
}
/*
* The 'net.change' property is a special property used track when any
* 'net.*' property name is updated. It is _ONLY_ updated here. Its value
* contains the last updated 'net.*' property.
*/
property_set("net.change", name);
} else if (persistent_properties_loaded &&
strncmp("persist.", name, strlen("persist.")) == 0) {
char bootmode[PROP_VALUE_MAX];
ret = property_get("ro.bootmode", bootmode);
if (ret <= 0 || (strcmp(bootmode, "charger") != 0)) //do not write prop while charger mode
/*
* Don't write properties to disk until after we have read all default properties
* to prevent them from being overwritten by default values.
*/
write_persistent_property(name, value); // persistent属性,写到/data/property中
}
property_changed(name, value); // 查询init中是否有action被触发。 on property: xxx
return 0;
}