通过以上分析,只有property_service对properties有写的权限,其它地方都只有读取的权限,Bionic中虽然也可以Set,但是实际还是通过socket把命令发给property_service实现。
system/core/init/property_service.c
system/core/init/property_service.h
system/core/init/init.c
int main(int argc, char **argv)
{
//完成初始化环境变量等动作
property_init();
//启动property_service
queue_builtin_action(property_service_init_action, "property_service_init");
for(;;) {
if (!property_set_fd_init && get_property_set_fd() > 0) {
ufds[fd_count].fd = get_property_set_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
property_set_fd_init = 1;
}
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();
}
}
}
void service_start(struct service *svc, const char *dynamic_args)
{
if (properties_inited()) {
//如果初始化完成了,获取property_workspace
get_property_workspace(&fd, &sz);
sprintf(tmp, "%d,%d", dup(fd), sz);
//将得到的property_workspace写入到环境变量ANDROID_PROPERTY_WORKSPACE
//是不是很熟悉,它就是Bionic中实现mmap时需要得到的ANDROID_PROPERTY_WORKSPACE
//这样,client和server的memory就shared了
add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
}
}
//property_service 初始化
void property_init(void)
{
init_property_area();
}
static int init_property_area(void)
{
prop_area *pa;
if(pa_info_array)
return -1;
//初始化workspace,得到shared memory的fd,size,data
if(init_workspace(&pa_workspace, PA_SIZE))
return -1;
fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
pa_info_array = (void*) (((char*) pa_workspace.data) + PA_INFO_START);
//pa指向shared memory的头,实际就是头信息,并初始化
pa = pa_workspace.data;
memset(pa, 0, PA_SIZE);
pa->magic = PROP_AREA_MAGIC;
pa->version = PROP_AREA_VERSION;
/* plug into the lib property services */
__system_property_area__ = pa;
property_area_inited = 1;
return 0;
}
static int init_workspace(workspace *w, size_t size)
{
/* dev is a tmpfs that we can use to carve a shared workspace
* out of, so let's do that...
*/
//创建一个临时的设备
fd = open("/dev/__properties__", O_RDWR | O_CREAT, 0600);
if (ftruncate(fd, size) < 0)
goto out;
//从kernel中映射出一块内存
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
fd = open("/dev/__properties__", O_RDONLY);
//删除掉临时的设备,但是映射的内存还是存在,fd被保存下来,而且只有data这个mmap有读写的权限
//其它人得到的fd都是只读的,而且/dev/__properties__已经被删除了,其它人已经不能在得到写权限了。
unlink("/dev/__properties__");
w->data = data;
w->size = size;
w->fd = fd;
return 0;
out:
close(fd);
return -1;
}
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
void start_property_service(void)
{
int fd;
//load_properties_from_file就是从文件中读取key和value,并把他们property_set(key, value);
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 /* ALLOW_LOCAL_PROP_OVERRIDE */
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
//PROP_SERVICE_NAME又是很熟悉的名字,在Bionic中的send_prop_msg时,会连接PROP_SERVICE_NAME
//并发送命令,server端就是在这里实现的
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);
listen(fd, 8);
property_set_fd = fd;
}
const char* property_get(const char *name)
{
prop_info *pi;
if(strlen(name) >= PROP_NAME_MAX) return 0;
pi = (prop_info*) __system_property_find(name);
if(pi != 0) {
return pi->value;
} else {
return 0;
}
}
property_set可以在init.c中直接被调用。
在init.c中:
int main(int argc, char **argv)
{
//完成初始化环境变量等动作
property_init();
//启动property_service
queue_builtin_action(property_service_init_action, "property_service_init");
for(;;) {
if (!property_set_fd_init && get_property_set_fd() > 0) {
ufds[fd_count].fd = get_property_set_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
property_set_fd_init = 1;
}
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_set,server会收到从Bionic中发送的PROP_MSG_SETPROP命令,收到后,检查权限,然后调用property_set进行设置。 void handle_property_set_fd()
{
if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
return;
}
/* Check socket options here */
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
ERROR("Unable to recieve socket options\n");
return;
}
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
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) {
// Keep the old close-socket-early behavior when handling
// ctl.* properties.
close(s);
//检查控制命令的权限
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 gid:%d pid:%d\n",
msg.name + 4, msg.value, cr.uid, cr.gid, 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);
}
// 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);
}
break;
default:
close(s);
break;
}
}
可以在Property中设定控制命令,实现某个service的start和stop,在命令行中也可以通过start和stop命令实现某个service的start和stop
void handle_control_message(const char *msg, const char *arg)
{
if (!strcmp(msg,"start")) {
msg_start(arg);
} else if (!strcmp(msg,"stop")) {
msg_stop(arg);
} else if (!strcmp(msg,"restart")) {
msg_stop(arg);
msg_start(arg);
} else {
ERROR("unknown control msg '%s'\n", msg);
}
}
int property_set(const char *name, const char *value)
{
pi = (prop_info*) __system_property_find(name);
if(pi != 0) {
//ro,只读的property只能被设定一次
/* ro.* properties may NEVER be modified once set */
if(!strncmp(name, "ro.", 3)) return -1;
update_prop_info(pi, value, valuelen);
pa->serial++;
__futex_wake(&pa->serial, INT32_MAX);
} else {
//将key和value写入到shared memory中
pa = __system_property_area__;
if(pa->count == PA_COUNT_MAX) return -1;
pi = pa_info_array + pa->count;
pi->serial = (valuelen << 24);
memcpy(pi->name, name, namelen + 1);
memcpy(pi->value, value, valuelen + 1);
pa->toc[pa->count] =
(namelen << 24) | (((unsigned) pi) - ((unsigned) pa));
pa->count++;
pa->serial++;
__futex_wake(&pa->serial, INT32_MAX);
}
}