looper
循环器,loop
环,poll
调查。
Android Looper是使用Linux的IO事件处理机制epoll实现的。
Looper框架以so的形式提供给Android系统使用,源代码位于下面的路径:
system/core/libutils/include/utils/Looper.h system/core/libutils/Looper.cpp
Android的Looper框架,包括几个组件,分别是:Message、MessageHandler、Looper。Message
是消息实体,MessageHandler
是处理消息的回调,Looper
是消息机制的核心。
Android的Java层的消息机制就是通过调用这个库实现的,所以Android的消息机制实际是使用Linux的IO事件处理机制epoll实现的。
使用方法
创建Looper对象
Looper mLooper = new Looper(false);
添加/删除要检测的文件描述符
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); mLooper->removeFd(inputChannel->getFd());
等待回调、超时或唤醒
mLooper->pollOnce(timeoutMillis);
主动唤醒
mLooper->wake();
发送、删除消息
mLooper->sendMessage(handler, message);
Looper机制主逻辑
Loop构造方法
system/core/libutils/Looper.cpp
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
// 创建一个文件句柄,用于唤醒
mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
//
rebuildEpollLocked();
}
void Looper::rebuildEpollLocked() {
// 分配/创建 一个新的epoll实例
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeEventFd;
// 添加用于唤醒的文件句柄mWakeEventFd到epoll
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
// 添加所有request.fd到epoll
for (size_t i = 0; i < mRequests.size(); i++) {
const Request& request = mRequests.valueAt(i);
struct epoll_event eventItem;
request.initEventItem(&eventItem);
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
if (epollResult < 0) {
ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
request.fd, strerror(errno));
}
}
}
添加删除要检测的文件描述符
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
if (!callback.get()) {
if (! mAllowNonCallbacks) {
ALOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
return -1;
}
if (ident < 0) {
ALOGE("Invalid attempt to set NULL callback with ident < 0.");
return -1;
}
} else {
// 一般会走这里,ident=-2,callback不为空
ident = POLL_CALLBACK;
}
{ // acquire lock
AutoMutex _l(mLock);
// 根据传参,创建Request对象并赋值
Request request;
request.fd = fd;
request.ident = ident;
request.events = events;
request.seq = mNextRequestSeq++;
request.callback = callback; // 这个回调需要留意,当这个fd上有事件触发时,就会调用这个callback
request.data = data;
if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1
struct epoll_event eventItem;
// 根据request参数初始化eventItem
request.initEventItem(&eventItem);
// 查看本次创建的request是否已经在mRequest中存在
ssize_t requestIndex = mRequests.indexOfKey(fd);
// 小于0表示不存在,然后将文件句柄加入epoll,并把request加入mRequest
if (requestIndex < 0) {
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
if (epollResult < 0) {
ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
return -1;
}
mRequests.add(fd, request);
} else {
// 大于等于0说明已经存在,修改epoll中的这个文件句柄,然后更新mRequest中的这个request
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
if (epollResult < 0) {
if (errno == ENOENT) {
// 修改失败,进行添加操作
epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
if (epollResult < 0) {
ALOGE("Error modifying or adding epoll events for fd %d: %s",
fd, strerror(errno));
return -1;
}
scheduleEpollRebuildLocked();
} else {
ALOGE("Error modifying epoll events for fd %d: %s", fd, strerror(errno));
return -1;
}
}
mRequests.replaceValueAt(requestIndex, request);
}
} // release lock
return 1;
}
这个需要留意传入的参数LooperCallback,当fd上有事件触发的时候,这个callback就会被调用。
int Looper::removeFd(int fd, int seq) {
{ // acquire lock
AutoMutex _l(mLock);
// 检查fd是否在mRequest中,如果不存在,无需删除,直接返回
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
return 0;
}
// 如果设置了seq参数,需要检查和要删除的是否一致。不设置的话,会使用默认值-1
if (seq != -1 && mRequests.valueAt(requestIndex).seq != seq) {
return 0;
}
// 从mRequests中删除这个句柄的request
mRequests.removeItemsAt(requestIndex);
// 从epoll中删除这个句柄
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
if (epollResult < 0) {
if (seq != -1 && (errno == EBADF || errno == ENOENT)) {
scheduleEpollRebuildLocked();
} else {
scheduleEpollRebuildLocked();
return -1;
}
}
} // release lock
return 1;
}
等待回调、超时或唤醒
inline int pollOnce(int timeoutMillis) {
return pollOnce(timeoutMillis, NULL, NULL, NULL);
}
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
result = pollInner(timeoutMillis);
}
}
int Looper::pollInner(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif
// 计算调整timeout时间
if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
if (messageTimeoutMillis >= 0
&& (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
timeoutMillis = messageTimeoutMillis;
}
}
// Poll.
int result = POLL_WAKE;
mResponses.clear();
mResponseIndex = 0;
// 设置标志变量mPolling,标志进入idle状态
mPolling = true;
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
// 进入等待状态
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
// 设置标志变量mPolling,标志退出idle状态
mPolling = false;
// 如果返回的事件数量小于0,说明发生了错误,直接返回
if (eventCount < 0) {
if (errno == EINTR) {
goto Done;
}
ALOGW("Poll failed with an unexpected error: %s", strerror(errno));
result = POLL_ERROR;
goto Done;
}
// 如果返回的事件数量是0,说明超时了
if (eventCount == 0) {
result = POLL_TIMEOUT;
goto Done;
}
for (int i = 0; i < eventCount; i++) {
// 取得发生事件的文件句柄fd
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
// 如果文件句柄是用于唤醒epoll的mWakeEventFd
if (fd == mWakeEventFd) {
// 没有啥实际逻辑
if (epollEvents & EPOLLIN) {
awoken();
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
}
} else {
// else说明是request fd 事件返回了
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex >= 0) {
int events = 0;
if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
// 将返回的事件放入向量mResponses
pushResponse(events, mRequests.valueAt(requestIndex));
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
"no longer registered.", epollEvents, fd);
}
}
}
Done: ;
// 处理message
mNextMessageUptime = LLONG_MAX;
while (mMessageEnvelopes.size() != 0) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
// 如果消息的预计被处理时间已经到了
if (messageEnvelope.uptime <= now) {
{ // obtain handler
sp<MessageHandler> handler = messageEnvelope.handler;
Message message = messageEnvelope.message;
mMessageEnvelopes.removeAt(0);
mSendingMessage = true;
mLock.unlock();
// 调用handler的回调方法handleMessage()处理消息
handler->handleMessage(message);
} // release handler
mLock.lock();
mSendingMessage = false;
result = POLL_CALLBACK;
// 如果消息的预计被处理时间还没到,就用这个消息的实际设置mNextMessageUptime(下一次唤醒epoll的时间),然后退出消息处理
} else {
// 消息队列的第一个消息决定epoll/Looper的唤醒时间
mNextMessageUptime = messageEnvelope.uptime;
break;
}
}
// Release lock.
mLock.unlock();
// 处理response,调用发生事件fd的callback
for (size_t i = 0; i < mResponses.size(); i++) {
Response& response = mResponses.editItemAt(i);
if (response.request.ident == POLL_CALLBACK) {
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
// Invoke the callback. Note that the file descriptor may be closed by
// the callback (and potentially even reused) before the function returns so
// we need to be a little careful when removing the file descriptor afterwards.
int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
removeFd(fd, response.request.seq);
}
// Clear the callback reference in the response structure promptly because we
// will not clear the response vector itself until the next poll.
response.request.callback.clear();
result = POLL_CALLBACK;
}
}
return result;
}
这里需要关注epoll_wait的超时时间,这个时间不一定是方法传入参数的时间,也可以是下一个消息预计被处理的时间,哪个小就设置为超时时间。
主动唤醒
void Looper::wake() {
uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
}
通过向epoll监听的唤醒文件句柄mWakeEventFd里面写入1。
主动唤醒是应用程序发起的,超时和回调都是kernel发起的。
添加、删除消息
void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
sendMessageAtTime(now, handler, message);
}
void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
const Message& message) {
size_t i = 0;
{ // acquire lock
AutoMutex _l(mLock);
// mMessageEnvelopes是存放消息的数据结构,是一个向量容器
size_t messageCount = mMessageEnvelopes.size();
while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
i += 1;
}
// 创建一个messageEnvelope
MessageEnvelope messageEnvelope(uptime, handler, message);
// 按照时间顺序(由小到大)添加到mMessageEnvelopes
mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
} // release lock
// 如果在消息队里的开始的位置添加了一个消息,就唤醒Looper loop
// 唤醒之后pollInner()方法的epoll_wait行会返回并继续执行,消息的处理逻辑就在后面
if (i == 0) {
wake();
}
}
其它重要方法
sp<Looper> Looper::prepare(int opts) {
bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS;
sp<Looper> looper = Looper::getForThread();
// 如果looper没有创建过,就创建一个;否则,直接返回
if (looper == NULL) {
looper = new Looper(allowNonCallbacks);
Looper::setForThread(looper);
}
return looper;
}
void Looper::setForThread(const sp<Looper>& looper) {
sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
if (looper != NULL) {
looper->incStrong((void*)threadDestructor);
}
// 设置gTLSKey对应的looper
pthread_setspecific(gTLSKey, looper.get());
if (old != NULL) {
old->decStrong((void*)threadDestructor);
}
}
sp<Looper> Looper::getForThread() {
// 同一个线程中,pthread_once只执行一次,执行initTLSKey()方法得到gTLSKey(thread looper static key)
int result = pthread_once(& gTLSOnce, initTLSKey);
LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
// 取得gTLSKey对应的Looper
return (Looper*)pthread_getspecific(gTLSKey);
}
void Looper::initTLSKey() {
int result = pthread_key_create(& gTLSKey, threadDestructor);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key.");
}
通过pthread_once和pthread_key_create保证一个线程中只生成一个thread looper static key(static);通过pthread_setspecific/pthread_getspecific来设置和取得thread looper static key对应的looper。即通过这里,可以保证一个线程只创建一个looper,并且looper和线程是绑定的,可以通过thread looper static key取得线程的looper。
涉及的数据结构
Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
// Locked list of file descriptor monitoring requests.
KeyedVector<int, Request> mRequests; // guarded by mLock
// This state is only used privately by pollOnce and does not require a lock since
// it runs on a single thread.
Vector<Response> mResponses;
Android Lopper涉及三个用来存储数据,都是向量。mRequests用来存储所有加入epoll的请求。mResponses存储所有epoll返回的事件。mMessageEnvelopes。
涉及的知识点
线程数据共享
pthread_getpecific和pthread_setspecific提供了在同一个线程中不同函数间共享数据即线程存储的一种方法。具体用法为:
- 调用pthread_key_create()来创建一个类型为pthread_key_t类型的变量
该函数有两个参数,第一个参数就是声明的pthread_key_t变量,第二个参数是一个清理函数,用来在线程释放该线程存储的时候被调用。该函数指针可以设成NULL,这样系统将调用默认的清理函数。
- 调用pthread_setspcific()
当线程中需要存储特殊值的时候调用该函数,该函数有两个参数,第一个为前面声明的pthread_key_t变量,第二个为void*变量,用来存储任何类型的值。
- 如果需要取出所存储的值,调用pthread_getspecific()
该函数的参数为前面提到的pthread_key_t变量,该函数返回void*类型的值。
pthread_once
在多线程环境中,有些事仅需要执行一次。通常当初始化应用程序时,可以比较容易地将其放在main函数中。但当你写一个库时,就不能在main里面初始化了,你可以用静态初始化,但使用一次初始化(pthread_once)会比较容易些。
int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));
功能:本函数使用初值为PTHREAD_ONCE_INIT的once_control变量保证init_routine()函数在本进程执行序列中仅执行一次。 在多线程编程环境下,尽管pthread_once()调用会出现在多个线程中,init_routine()函数仅执行一次,究竟在哪个线程中执行是不定的,是由内核调度来决定。
epoll
最重要的知识点是Linux的IO事件处理机制epoll(暂缺)。