博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《Android的设计与实现:卷I》——第3章 3.6init循环监听处理事件
阅读量:6298 次
发布时间:2019-06-22

本文共 3307 字,大约阅读时间需要 11 分钟。

3.6 init循环监听处理事件

init触发所有Action后,便进入一个无限循环,在这个无限循环里首先执行两条指令:

execute_one_command()和restart_processes()。
其中execute_one_command()已经分析过,用来启动Action和Service;restart_processes()也容易理解,就是重启这些Action和Service。此后便在init中调用了系统函数poll等待一些事件发生,代码如下:
nr = poll(ufds, fd_count, timeout);//poll返回
……//省略部分内容
for (i = 0; i < fd_count; i++) {//轮询这几个Socket
if (ufds[i].revents == POLLIN) {//可读事件

/如果可读事件发生在property  fd这个Socket上,便执行handle_property_set_fd 函数/  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上的事件,那么它都监听了哪些fd呢?这些fd都是由ufds指定的,代码如下:
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) {     …… }

分别调用get_property_set_fd、get_signal_fd、get_keychord_fd监听了3个fd,其中get_property

set_fd便是属性服务里启动的那个Socket,后续处理中用于属性设置等操作;get_signal_fd用于获得子进程退出信号,后续处理中用于回收子进程资源或者重启子进程(Service)。下面以get_property_set_fd为例分析这部分内容的处理机制。

当start_property_service中创建的Socket上有可读事件发生时,init中的poll函数监控到可读事件发生,便开始执行handle_property_set_fd函数,该函数位于property_service.c中,代码如下:

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);/接收property_set_fd上的连接请求,accept是标准的Socket编程函数/if ((s = accept(property_set_fd, (struct sockaddr ) &addr, &addr_size)) < 0) {    return;}……//省略部分内容/recv接收请求数据/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;    /如果消息名以ctl.开头,则认为是control message(控制消息),调用     check_control_perms函数检查权限,如果满足权限要求则执行     handle_control_message设置消息。这部分消息其实控制的是Service     的开启和关闭/     if(memcmp(msg.name,"ctl.",4) == 0) {        close(s);        if (check_control_perms(msg.value, cr.uid, cr.gid)) {            handle_control_message((char) msg.name + 4, (char) msg.value);        } else {           ……//省略部分内容        }    } else {       /其他类型消息,需要通过check_perms 检查权限,然后直接调用        property_set函数设置属性 /        if (check_perms(msg.name, cr.uid, cr.gid)) {            property_set((char) msg.name, (char) msg.value);        } else {           ……//省略部分内容        }        close(s);    }    break;default:    close(s);    break;}

}

可见当属性服务器接收到客户端请求后,init中的poll函数监控到可读事件,这时候它会返回,然后判断是property fd这个Socket上发生了可读事件,之后便会在init的handle_property_set_fd方法中处理请求。
handle_property_set_fd函数中主要做了两部分工作:首先通过accept和recv这两个标准的Socket编程函数接受并取得客户端消息,然后根据消息类型分别调用鉴权函数和属性设置函数,设置属性或启动相应的服务。这样做的好处是避免了客户端只能通过init修改属性值,也避免了直接操作属性服务带来的安全问题。
至此init的启动过程就分析完了。

3.7 本章小结

本章详细分析了Android启动过程的底层实现。首先以Kernel启动过程为入口点,分析了start_kernel如何被调用,init如何被启动;接着将init启动过程分为四大部分,重点分析了其中三个部分:解析init.rc、触发并启动Action和Service、循环处理事件;然后围绕这三大部分详细分析了Android初始化语言,如何解析Service和Action,如何触发Action,如何启动Action和Service,如何启动属性服务,以及init如何在循环中等待处理属性系统和信号系统的事件。

第4章将接着本章的内容继续分析Android启动过程上层实现。

转载地址:http://quqta.baihongyu.com/

你可能感兴趣的文章
算法复习之坐标离散化
查看>>
网络通信
查看>>
数据包重放
查看>>
==和===的区别
查看>>
使用JQuery Autocomplete插件(一)
查看>>
Weblogic Admin Console
查看>>
JS框架设计之命名空间设计一种子模块
查看>>
javascript 事件对象
查看>>
分分钟搞定 JSP 技术
查看>>
python多进程模板
查看>>
【转载】大连商品交易所-新套利撮合算法FAQ
查看>>
ubuntu笔记 - 安装和配置Sublime Text
查看>>
Sqlserver__数据表排序记录和界面显示排序记录不一致的问题
查看>>
FreeSWITCH异常原因总结
查看>>
统计项目总行数
查看>>
JQuery
查看>>
uva 544(kruskal 变形)
查看>>
poj 3692(二分图匹配--最大独立集)
查看>>
快速索引 (对View的自定义)
查看>>
关于Arrays类总结
查看>>