property ro.xxx属性介绍
ro的英文缩写是Read Only,故在Android系统中,带有ro.的属性都是只读而不可被重复修改的。ro.xxx属性的property通常在系统启动的时候就通过property_set()函数被写在了系统中,而ro属性每次系统启动只能写一次,顾一但设定便不可修改。
setprop
在system/core/toobox下有许多常用的命令的源码,setprop由setprop.c生成
#include
#include
int setprop_main(int argc, char *argv[])
{
if(argc != 3) {
fprintf(stderr,"usage: setprop \n");
return 1;
}
if(property_set(argv[1], argv[2])){
fprintf(stderr,"could not set property\n");
return 1;
}
return 0;
}
setprop调用了property_set(const char key, const char value)函数,该函数位于system/core/libcutils下,在这里,最后跳转到了__system_property_set函数。
#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include
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)
{
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;
prop_msg msg;
memset(&msg, 0, sizeof msg);
msg.cmd = PROP_MSG_SETPROP;
strlcpy(msg.name, key, sizeof msg.name);
strlcpy(msg.value, value, sizeof msg.value);
const int err = send_prop_msg(&msg);
if (err < 0) {
return err;
}
return 0;
}
由于property_set与prop系统服务进程的通信方式主要是通过socket来设置对应的property,而__system_property_set主要作用便是与prop系统服务进程进行通信的。如上代码中,该函数通过send_prop_msg函数发送PROP_MSG_SETPROP命令告知prop系统服务进程写入property。send_prop_msg()函数通过存放在/dev/socket/下的socket本地套接字与服务进程通信。
switch(msg.cmd) {
case PROP_MSG_SETPROP:
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
if (!is_legal_property_name(msg.name, strlen(msg.name))) {
ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
close(s);
return;
}
使ro属性可重复被修改
在服务进程接收到客户端发来的PROP_MSG_SETPROP命令时,服务进程会判断将要修改的property是否是ro属性,如果是ro属性且已经存在程序直接返回,对property不做任何修改。
通过修改system/core/init/property_service.c 下的void handle_property_set_fd()函数
switch(msg.cmd) {
case PROP_MSG_SETPROP:
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
if (!is_legal_property_name(msg.name, strlen(msg.name))) {
ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
close(s);
return;
}
getpeercon(s, &source_ctx);
if(memcmp(msg.name,"ctl.",4) == 0) {
// Keep the old close-socket-early behavior when handling
// ctl.* properties.
close(s);
if (check_control_mac_perms(msg.value, 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 {
if (check_perms(msg.name, source_ctx)
|| (0 == strcmp(msg.name, "ro.serialno"))
|| (0 == strcmp(msg.name, "ro.deviceid"))) //mod to let 'ro.xxx' can be modifiy
{
property_set((char*) msg.name, (char*) msg.value);
} else {
ERROR("sys_prop: permission denied uid:%d name:%s\n",
cr.uid, msg.name);
}
// Note: bionic's property client code assumes that the
// property server will not close the socket until *AFTER*
// the property is written to memory.
close(s);
以及int property_set(const char name, const char value)函数
int property_set(const char *name, const char *value)
{
prop_info *pi;
int ret;
size_t namelen = strlen(name);
size_t valuelen = strlen(value);
if (!is_legal_property_name(name, namelen)) return -1;
if (valuelen >= PROP_VALUE_MAX) return -1;
pi = (prop_info*) __system_property_find(name);
if(pi != 0) {
/* ro.* properties may NEVER be modified once set */
if((0 == strcmp(name, "ro.serialno"))
|| (0 == strcmp(name, "ro.deviceid")))//mod to let 'ro.xxx' can be modifiy
{;;}
else if (!strncmp(name, "ro.", 3) ) return -1;
//if(!strncmp(name, "ro.", 3) ) return -1;
__system_property_update(pi, value, valuelen);
} else {
ret = __system_property_add(name, namelen, value, valuelen);
if (ret < 0) {
ERROR("Failed to set '%s'='%s'\n", name, value);
return ret;
}
}
这样就可以实现对特定ro属性的property进行多次修改!
修改Android源码使property中ro属性可重复修改