《Android的设计与实现:卷I》——第3章 3.6init循环监听处理事件

简介: 本节书摘来自华章出版社《Android的设计与实现:卷I》——第3章,第3.5节。作者: 杨云君著.更多章节内容可以访问云栖社区“华章计算机”公众号查看。

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启动过程上层实现。

相关文章
|
4月前
|
XML Java Android开发
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
38 0
“framework必会”系列:Android Input系统(一)事件读取机制
曾经在开发的很长一段时间内,笔者对点击事件的认知只存在于自定义View中的`onTouchEvent`等方法的处理。 后来慢慢的接触到`Android的事件分发机制`,但也只是在**Activity->ViewGroup->View**层面的分发逻辑
|
4月前
|
小程序 JavaScript 前端开发
微信小程序(十七)小程序监听返回键跳转事件(安卓返回也适用)
onUnload:function(){ wx.redirectTo({ url: '../index/index' }) wx.navigateTo({ url: '../index/index' }) wx.switchTab({ url: '../../member/member' }) }
297 0
|
4月前
|
XML Java Android开发
Android App事件交互Event之模仿京东App实现下拉刷新功能(附源码 可直接使用)
Android App事件交互Event之模仿京东App实现下拉刷新功能(附源码 可直接使用)
32 0
Android App事件交互Event之模仿京东App实现下拉刷新功能(附源码 可直接使用)
|
4月前
|
XML Java Android开发
Android App事件交互中辨别缩放与旋转手指的讲解与实战(附源码 可直接使用)
Android App事件交互中辨别缩放与旋转手指的讲解与实战(附源码 可直接使用)
35 0
|
4月前
|
XML Java Android开发
Android App事件交互中区分点击和长按动作以及识别手势滑动方向的讲解及实战(附源码 可直接使用)
Android App事件交互中区分点击和长按动作以及识别手势滑动方向的讲解及实战(附源码 可直接使用)
56 0
|
4月前
|
XML Java Android开发
Android App开发触摸事件中手势事件Event的分发流程讲解与实战(附源码 简单易懂)
Android App开发触摸事件中手势事件Event的分发流程讲解与实战(附源码 简单易懂)
43 0
|
4月前
|
XML 监控 Java
Android App开发之事件交互Event中检测软键盘和物理按键讲解及实战(附源码 演示简单易懂)
Android App开发之事件交互Event中检测软键盘和物理按键讲解及实战(附源码 演示简单易懂)
112 0
|
7月前
|
Shell Android开发
Android init language与init.rc初始化脚本
Android init language与init.rc初始化脚本
52 0
|
8月前
|
Android开发
Android 获取include标签中的控件属性并设置事件
Android 获取include标签中的控件属性并设置事件
137 0