行相应的初始化工作。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进程