android ctl属性的实现过程

对于android开机动画的启动和停止,在代码中是通过调用property_service.c中的property_set实现的,代码如下:

  property_set(“ctl.start”, “bootanim”);

  property_set(“ctl.stop”, “bootanim”);

 

当然也可以通过命令行来控制,命令如下:

 

#setprop ctl.start bootanim

#setprop ctl.stop bootanim

 

其实通过控制ctl.startctl.stop这两个属性,不仅仅可以控制开机动画,还可以控制init.rc文件中定义的各种service

 

ctl.xxx是怎么样实现start或者stop一个service的呢?

 

Androidinit进程在启动的过程当中会通过start_property_service函数创建一个属性服务的socket,这个socket描述符为/dev/socket/

property_service,系统中对属性的操作都会以请求的形式发给这个socket, start_property_service函数代码如下:

 

void start_property_service(void)

{

    int fd;

 

    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);

    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);

    load_override_properties();

    /* Read persistent properties after all default values have been loaded. */

    load_persistent_properties();

 

    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;

}

 

 

那这些请求是在哪里被处理呢?也是在init进程当中。

 

Init进程启动的最后,会进入一个循环结构,代码如下:

 

    for(;;) {

        int nr, i, timeout = -1;

 

        execute_one_command();

        restart_processes();

 

        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;

        }

        if (!signal_fd_init && get_signal_fd() > 0) {

            ufds[fd_count].fd = get_signal_fd();

            ufds[fd_count].events = POLLIN;

            ufds[fd_count].revents = 0;

            fd_count++;

            signal_fd_init = 1;

        }

        if (!keychord_fd_init && get_keychord_fd() > 0) {

            ufds[fd_count].fd = get_keychord_fd();

            ufds[fd_count].events = POLLIN;

            ufds[fd_count].revents = 0;

            fd_count++;

            keychord_fd_init = 1;

        }

 

        if (process_needs_restart) {

            timeout = (process_needs_restart - gettime()) * 1000;

            if (timeout < 0)

                timeout = 0;

        }

 

        if (!action_queue_empty() || cur_action)

            timeout = 0;

 

#if BOOTCHART

        if (bootchart_count > 0) {

            if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)

                timeout = BOOTCHART_POLLING_MS;

            if (bootchart_step() < 0 || --bootchart_count == 0) {

                bootchart_finish();

                bootchart_count = 0;

            }

        }

#endif

 

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

            }

        }

    }

 

这个循环体就一直在poll几个fd,其中有一个就是上面讲的属性服务的socket, handle_property_set_fd的代码如下:

 

void handle_property_set_fd()

{

    prop_msg msg;

    int s;

    int r;

    int res;

    struct ucred cr;

    struct sockaddr_un addr;

    socklen_t addr_size = sizeof(addr);

    socklen_t cr_size = sizeof(cr);

    char * source_ctx = NULL;

 

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

    if(r != sizeof(prop_msg)) {

        ERROR("sys_prop: mis-match msg size recieved: %d expected: %d errno: %d\n",

              r, sizeof(prop_msg), errno);

        close(s);

        return;

    }

 

    switch(msg.cmd) {

    case PROP_MSG_SETPROP:

        msg.name[PROP_NAME_MAX-1] = 0;

        msg.value[PROP_VALUE_MAX-1] = 0;

 

#ifdef HAVE_SELINUX

        getpeercon(s, &source_ctx);

#endif

 

 

        //如果是对ctl.xxx属性的请求,则最后会调用init.c文件定义的service_start或者service_stop函数来运行或者停止一个service

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

            }

 

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

        }

#ifdef HAVE_SELINUX

        freecon(source_ctx);

#endif

 

        break;

 

    default:

        close(s);

        break;

    }

}

 

 

 

这样通过设置ctl.start或者ctl.stop属性就可以达到启动或者停止service的目的。

 

 

发布了13 篇原创文章 · 获赞 4 · 访问量 5万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览