背景
從 Android 2.3 開始熙揍,Google 把 Handler 的阻塞/喚醒方案從 Object#wait() / notify()阴孟,改成了用 Linux epoll 來(lái)實(shí)現(xiàn)
流程
1漆枚、epoll涉及到3個(gè)重要方法
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
2、在java層Handler的MessageQueue類有3個(gè)本地方法
class MessageQueue {
private native static long nativeInit();
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
private native static void nativeWake(long ptr);
}
3寺鸥、在Handler的native層也有對(duì)應(yīng)的MessageQueue、Looper、Handler秘血,在native層Looper的構(gòu)造方法里
- 調(diào)用epoll_create()方法創(chuàng)建了mEpollFd(epoll 對(duì)象)
- 調(diào)用epoll_ctl()方法mWakeEventFd(喚醒隊(duì)列作用)注冊(cè)到mEpollFd(epoll池)
/system/core/libutils/Looper.cpp
class looper {
Looper::Looper() {
int mWakeEventFd = eventfd();
rebuildEpollLocked();
}
void rebuildEpollLocked(){
創(chuàng)建了 epoll 對(duì)象
int mEpollFd = epoll_create();
mWakeEventFd(喚醒隊(duì)列作用)注冊(cè)到mEpollFd(epoll池)
epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
}
}
4、在java層的MessageQueue類調(diào)用本地方法 nativePollOnce()的時(shí)候评甜,最終調(diào)用是native層Looper的pollOnce()方法輪詢
- 如果沒(méi)有消息 epoll_wait() 使線程進(jìn)入到阻塞態(tài)灰粮,讓出 CPU 調(diào)度
/frameworks/base/core/jni/android_os_MessageQueue.cpp
class android_os_MessageQueue {
//jni方法,轉(zhuǎn)到 NativeMessageQueue#pollOnce()
void android_os_MessageQueue_nativePollOnce(){
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
class NativeMessageQueue : MessageQueue {
Looper#pollOnce() 方法
void pollOnce(){
mLooper->pollOnce(timeoutMillis);
}
}
}
//system/core/libutils/Looper.cpp
class looper {
int pollOnce(int timeoutMillis){
int result = 0;
for (;;) {
if (result != 0) {
return result;
}
result = pollInner(timeoutMillis);//超時(shí)
}
}
int pollInner(int timeoutMillis){
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
}
}
5忍坷、在java層如果有新的消息插入粘舟,會(huì)調(diào)用的native層的wake()方法
/system/core/libutils/Looper.cpp
class looper {
void Looper::wake() {
int inc = 1;
write(mWakeEventFd, &inc);
}
}
這個(gè)時(shí)候mWakeEventFd寫入了1,狀態(tài)由不可讀變成可讀佩研,內(nèi)核監(jiān)聽(tīng)到fd讀寫狀態(tài)的改變柑肴,會(huì)觸發(fā) epoll_wait() 方法調(diào)用,epoll_wait() 就會(huì)解除阻塞狀態(tài)旬薯,繼續(xù)執(zhí)行