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

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

时间: 2024-09-23 13:36:02

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

Android实现美团、大众点评的购买悬浮效果(ScrollView滚动监听)

随着移动互联网的快速发展,它已经和我们的生活息息相关了,在公交地铁里面都能看到很多人的人低头看着自己的手机屏幕,从此"低头族"一词就产生了,作为一名移动行业的开发人员,我自己也是一名"低头族",上下班时间在公交地铁上看看新闻来打发下时间,有时候也会看看那些受欢迎的App的一些界面效果,为什么人家的app那么受欢迎?跟用户体验跟UI设计也有直接的关系,最近在美团和大众点评的App看到如下效果,我感觉用户好,很人性化,所以自己也尝试着实现了下,接下来就讲解下实现思路!

《Android的设计与实现:卷I》——第3章 3.5触发并启动Action和Service

3.5 触发并启动Action和Service init解析init.rc后,生成了存放Service和Action的链表.那么init又是如何控制这些Action和Service的呢?本节将详细分析这部分内容. 3.5.1 触发Action init解析完init.rc后,接着执行了action_for_each_trigger和queue_builtin_action.这两个函数做了些什么呢? 首先定位到action_for_each_trigger,其实现代码位于init_parser.c

《Android的设计与实现:卷I》——第3章 3.3init进程的执行过程

3.3 init进程的执行过程 init进程是用户空间的第一个进程,进程号为1.Android世界中,很多重要的工作都是从它开始的.init进程相关源码位于/system/core/init目录下,从其编译文件Android.mk中可以看到这部分源代码最终被编译为可执行文件init,代码如下: 注意 pollfd是Linux中定义的结构体,用于存放需要监控事件的文件描述符,其定义如下: struct pollfd { int fd; //需要监控的文件描述符 short events; //监控

Android监听获取应用的安装和卸载事件

Android 应用程序的安装和卸载事件,是由系统进行监听并全局广播的,支 持1.5(android 3)以上 因此,如果想要监听获取应用的安装和卸载事 件,只需要自定义一个BroadcastReceiver,来对系统广播进行监听和处理 BroadcastReceiver 是系统全局广播监听类, 其主要方法是onReceive (),自定义的广播类继承于它并实现自己的onReceive()处理逻辑 BroadcastReceiver 使用前,需要进行注册监听(xml和代码两种方式) ,不使用时需

Android 监听 WiFi 开关状态

Android 监听 WiFi 开关状态 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/70854309 本文出自[赵彦军的博客] WifiSwitch_Presenter 源码: package com.yiba.wifi.sdk.lib.presenter; import android.content.BroadcastReceiver; import android.content.Context; import and

Android编程双重单选对话框布局实现与事件监听方法示例

本文实例讲述了Android编程双重单选对话框布局实现与事件监听方法.分享给大家供大家参考,具体如下: 首先是自定义XML布局代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_pare

Android中应用前后台切换监听的实现详解

前言 最近在工作中遇到了这么一个需求:如何实现 Android 应用前后台切换的监听?下面来一起看看详细的介绍: iOS 内边是可以实现的,AppDelegate 给了一个回调监听: @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationWillResignActive(_ application: UIApplication) { // Sent when the a

Android 监听WiFi的开关状态实现代码

Android 监听WiFi的开关状态实现代码 WifiSwitch_Presenter 源码: package com.yiba.wifi.sdk.lib.presenter; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net

《Android的设计与实现:卷I》——第3章 Android启动过程的底层实现

第3章 Android启动过程的底层实现 Android支持多种启动模式,主要有正常模式(normal mode).安全模式(safe mode).恢复模式(recovery mode).工厂模式(factory mode).快速启动模式(fastboot mode)等.除正常模式外,都是刷机或者测试模式,本书只讲解正常模式下Android的启动过程.如果读者对其他启动模式感兴趣,可以自行查阅相关资料. 3.1 Android正常模式启动流程 Android的正常模式启动流程大体如下:步骤1 系