Android系统启动流程(一)解析init进程 下载本文

行相应的初始化工作。Android也提供了一个类似的机制,叫做属性服务。

在本文的开始,我们提到在init.cpp代码中和属性服务相关的代码有: system/core/init/init.cpp

property_init();

start_property_service();

这两句代码用来初始化属性服务配置并启动属性服务。首先我们来学习服务配置的初始化和启动。

属性服务初始化与启动

property_init函数具体实现的代码如下所示。 system/core/init/property_service.cpp

void property_init() {

if (__system_property_area_init()) {

ERROR(\ exit(1); } }

__system_property_area_init函数用来初始化属性内存区域。接下来查看start_property_service函数的具体代码:

void start_property_service() {

property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,

0666, 0, 0, NULL);//1 if (property_set_fd == -1) {

ERROR(\ exit(1); }

listen(property_set_fd, 8);//2

register_epoll_handler(property_set_fd, handle_property_set_fd);//3 }

注释1处用来创建非阻塞的socket。注释2处调用listen函数对property_set_fd进行监听,这样创建的socket就成为了server,也就是属性服务;listen函数的第二个参数设置8意味着属性服务最多可以同时为8个试图设置属性的用户提供服务。注释3处的代码将property_set_fd放入了epoll句柄中,用epoll来监听property_set_fd:当property_set_fd中有数据到来时,init进程将用handle_property_set_fd函数进行处理。

在linux新的内核中,epoll用来替换select,epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为内核中的select实现是采用轮询来处理的,轮询的fd数目越

多,自然耗时越多。

属性服务处理请求

从上文我们得知,属性服务接收到客户端的请求时,会调用handle_property_set_fd函数进行处理:

system/core/init/property_service.cpp

static void handle_property_set_fd() { ...

if(memcmp(msg.name,\ clowww.tt951.comse(s);

if (check_control_mac_perms(msg.value, source_ctx, &cr)) {

handle_control_message((char*) msg.name + 4, (char*) msg.value); } else {

ERROR(\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_mac_perms(msg.name, source_ctx, &cr)) {//1 property_set((char*) msg.name, (char*) msg.value);//2 } else {

ERROR(\ name:%s\\n\ cr.uid, msg.name); }

close(s); }

freecon(source_ctx); break; default:

close(s); break; } }

注释1处的代码用来检查客户端进程权限,在注释2处则调用property_set函数对属性进行修改,代码如下所示。

int property_set(const char* name, const char* value) { int rc = property_set_impl(name, value); if (rc == -1) {

ERROR(\ }

return rc; }

property_set函数主要调用了property_set_impl函数:

static int property_set_impl(const char* name, const char* value) { 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;

if (strcmp(\ if (selinux_reload_policy() != 0) {

ERROR(\ }

} else if (strcmp(\ if (restorecon_recursive(vanc630.comlue) != 0) {

ERROR(\ } }

//从属性存储空间查找该属性

prop_info* pi = (prop_info*) __system_property_find(name); //如果属性存在 if(pi != 0) {

//如果属性以\开头,则表示是只读,不能修改,直接返回 if(!strncmp(name, \ //更新属性值

__system_property_update(pi, value, valuelen); } else {

//如果属性不存在则添加该属性

int rc = __system_property_add(name, namelen, value, valuelen); if (rc < 0) { return rc; } }

/* If name starts with \ if (strncmp(\ { if (strcmp(\ return 0; }

//以net.开头的属性名称更新后,需要将属性名称写入net.change中 property_set(\ } else if (persistent_properties_loaded &&

strncmp(\ /*

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

property_changed(name, value); return 0; }

property_set_impl函数主要用来对属性进行修改,并对以ro、net和persist开头的属性进行相应的处理。到这里,属性服务处理请求的源码就讲到这。

8.init进程总结

讲到这,总结起来init进程主要做了三件事: 1.创建一些文件夹并挂载设备 2.初始化和启动属性服务

3.解析init.rc配置文件并启动zygote进程