本文将分析一下Looper类的实现及其应用,代码位于
frameworks/native/lib/utils/Looper.cpp。主要分为如下几个部分:
1. epoll系统调用接口简介
2. Looper类代码分析
3. Looper类应用实例分析
一、epoll系统调用接口简介
Looper事件机制实际上是依赖系统调用epoll实现的。它是一种I/O复用模型,即可以同时监控多个I/O事件。对于Looper来说,所谓的I/O事件就是所监控的文件描述符上没有有数据到达。epoll的主要接口如下所示 :
1. epoll_create():创建一个epoll实例,返回引用该实例的文件描述符。
原型如下所示 :
int epoll_create(int size ); |
参数size指定了我们想通过epoll实例监控文件描述符的数量。
2. epoll_ctl():操作与该epoll实例相关联的兴趣列表:添加一个文件描述符到兴趣列表中,从兴趣列表中删除一个现存的文件描述符以及修改事件掩码以决定要监控文件描述符上发生的哪个事件。
原型如下所示:
int epoll_ctl(int epfd , int op , int fd , struct epoll_event * ev ); |
其中参数op可以取如下一些值:
EPOLL_CTL_ADD |
将fd加入了监控列表 |
EPOLL_CTL_MOD |
修改当前监控的fd相关信息 |
EPOLL_CTL_DEL |
将fd从监控列表中删除 |
3. epoll_wait():从I/O Ready列表中返回与epoll实例相关联的项,即返回有事件发生的文件描述符的数量。
原型如下所示:
int epoll_wait(int epfd , struct epoll_event * evlist , int maxevents , int timeout ); |
其中timeout值为-1时,表示无限等待直到有事件发生。为0时,执行一个非阻塞检查后立即返回。大于0时,表示一个超时时间值。
另外,struct epoll_event结构定义如下所示 :
struct epoll_event {
uint32_t events; /* epoll events (bit mask) */
epoll_data_t data; /* User data */
};
主要的事件掩码有:
EPOLLIN:代表有数据可读
EPOLLOUT:代表有数据可写
epoll_data_t的数据结构定义如下:
typedef union epoll_data {
void *ptr; /* Pointer to user-defined data */
int fd; /*File descriptor */
uint32_t u32; /* 32-bit integer */
uint64_t u64; /* 64-bit integer */
} epoll_data_t;
使用实例:
int epfd;
struct epoll_event ev;
epfd = epoll_create(5);
if (epfd == -1)
errExit("epoll_create");
ev.data.fd = fd;
ev.events = EPOLLIN;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, ev) == -1)
errExit("epoll_ctl");
...
epoll_wait(...);
二、Looper类代码分析
Looper类定义了一种事件接口,这里所谓的事件就是文件描述符上的I/O数据是否可读或可写。它提供了一系列接口来支持事件通知和响应,通过轮询,利用epoll系统调用,可以侦测到发生在文件描述符上的I/O事件。
在分析Looper类之前,我们先来看两个与之相关的接口:
1. Looper消息处理接口。
class MessageHandler : public virtual RefBase {
protected:
virtual ~MessageHandler() { }
public:
/**
* Handles a message.
*/
virtual void handleMessage(const Message& message) = 0;
};
与之相关的Looper类的几个成员函数定义如下:
/**
* Enqueues a message to be processed by the specified handler.
*/
void sendMessage(const sp<MessageHandler>& handler, const Message& message);
/**
* Enqueues a message to be processed by the specified handler after all pending messages
* after the specified delay.
*/
void sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
const Message& message);
/**
* Enqueues a message to be processed by the specified handler after all pending messages
* at the specified time.
*/
void sendMessageAtTime(n