android properties分析(4) property_service 分析

property_service分析

通过以上分析,只有property_service对properties有写的权限,其它地方都只有读取的权限,Bionic中虽然也可以Set,但是实际还是通过socket把命令发给property_service实现。

system/core/init/property_service.c

system/core/init/property_service.h


property_service初始化

property_service的初始化动作的发起是在init中

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;
}


property_service启动

static int property_service_init_action(int nargs, char **args)
{   
    /* read any property files on system or data and
     * fire up the property service.  This must happen
     * after the ro.foo properties are set above so
     * that /data/local.prop cannot interfere with them.
     */
    start_property_service();
    return 0;
}

#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;
}


property_service中 property_get实现

实现很简单,直接调用的Bionic中的 __system_property_find,然后直接将value返回

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_service中 property_set实现

property_service中property_set,对于动态调用时,client实际调用的是handle_property_set_fd(),而不是 property_set。

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);
    }

}

你可能感兴趣的:(android properties分析(4) property_service 分析)