Android Handler機制系列文章整體內(nèi)容如下:
- Android Handler機制1之Thread
- Android Handler機制2之ThreadLocal
- Android Handler機制3之SystemClock類
- Android Handler機制4之Looper與Handler簡介
- Android Handler機制5之Message簡介與消息對象對象池
- Android Handler機制6之MessageQueue簡介
- Android Handler機制7之消息發(fā)送
- Android Handler機制8之消息的取出與消息的其他操作
- Android Handler機制9之Handler的Native實現(xiàn)前奏之Linux IO多路復用
- Android Handler機制10之Handdler的Native實現(xiàn)Native的實現(xiàn)
- Android Handler機制11之Handler機制總結(jié)
- Android Handler機制12之Callable、Future和FutureTask
- Android Handler機制13之AsyncTask源碼解析
一验靡、簡述
前面的文章講解了Java層的消息處理機制,其中MessageQueue類里面涉及到的多個Native方法,除了MessageQueue的native方法趋惨,native本身也有一套完整的消息機制,處理native消息惦蚊。在整個消息機制中器虾,MessageQueue是連接Java層和Native層的紐帶,換而言之蹦锋,Java層可以向MessageQueue消息隊列中添加消息兆沙,Native層也可以向MessageQueue消息隊列中添加消息。
Native的層關(guān)系圖:
二莉掂、MessageQueue
在MessageQueue的native方法如下:
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
private native static void nativeWake(long ptr);
private native static boolean nativeIsPolling(long ptr);
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
在Android Handler機制6之MessageQueue簡介中的五葛圃、native層代碼的初始化中 說了MessaegQueue構(gòu)造函數(shù)調(diào)用了nativeInit(),為了更好的理解,我們便從MessageQueue構(gòu)造函數(shù)開始說起
(一)库正、 nativeInit() 函數(shù)
nativeInit() 的主要作用是初始化曲楚,是在MessageQueue的構(gòu)造函數(shù)中調(diào)用
代碼在MessageQueue.java 68行
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
// 通過JNI調(diào)用了Native層的相關(guān)函數(shù),導致了NativeMessageQueue的創(chuàng)建
mPtr = nativeInit();
}
MessageQueue只是有一個構(gòu)造函數(shù)褥符,該構(gòu)造函數(shù)是包內(nèi)可見的洞渤,其內(nèi)部就兩行代碼,分別是設(shè)置了MessageQueue是否可以退出和native層代碼的相關(guān)初始化
在MessageQueue的構(gòu)造函數(shù)里面調(diào)用 nativeInit()属瓣,我們來看下
代碼在MessageQueue.java 61行
private native static long nativeInit();
根據(jù)Android跨進程通信IPC之3——關(guān)于"JNI"的那些事中知道,nativeInit這個native方法對應(yīng)的是android_os_MessageQueue.cpp里面的android_os_MessageQueue_nativeInit(JNIEnv* , jclass )函數(shù)
1讯柔、jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz)方法
代碼在android_os_MessageQueue.cpp 172 行
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
// 在Native層又創(chuàng)建了NativeMessageQueue
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return 0;
}
nativeMessageQueue->incStrong(env);
// 這里返回值是Java層的mPtr抡蛙,因此mPtr實際上是Java層MessageQueue與NativeMessesageQueue的橋梁
return reinterpret_cast<jlong>(nativeMessageQueue);
}
此時Java層和Native層的MessageQueue被mPtr連接起來了,NativeMessageQueue只是Java層MessageQueue在Native層的體現(xiàn)魂迄,其本身并沒有實現(xiàn)Queue的數(shù)據(jù)結(jié)構(gòu)粗截,而是從其父類MessageQueue中繼承mLooper變量。與Java層類型捣炬,這個Looper也是線程級別的單列熊昌。
代碼中是直接new 的NativeMessageQueue無參構(gòu)造函數(shù),那我們那就來看下
2湿酸、NativeMessageQueue無參構(gòu)造函數(shù)
NativeMessageQueue是android_os_MessageQueue.cpp的內(nèi)部類
代碼在android_os_MessageQueue.cpp 78行
NativeMessageQueue::NativeMessageQueue() : mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
// 獲取TLS中的Looper對象
mLooper = Looper::getForThread();
if (mLooper == NULL) {
// 創(chuàng)建native層的Looper對象
mLooper = new Looper(false);
// 保存native 層的Looper到TLS中(線程級單例)
Looper::setForThread(mLooper);
}
}
- Looper::getForThread():功能類比于Java層的Looper.myLooper();
- Looper::setForThread(mLooper):功能類比于Java層的ThreadLocal.set()
通過上述代碼我們知道:
- 1婿屹、Java層的Looper的創(chuàng)建導致了MessageQueue的創(chuàng)建,而在Native層則剛剛相反推溃,NativeMessageQueue的創(chuàng)建導致了Looper的創(chuàng)建
- 2昂利、MessageQueue是在Java層與Native層有著緊密的聯(lián)系,但是此次Native層的Looper與Java層的Looper沒有任何關(guān)系铁坎。
- 3蜂奸、Native層的Looper創(chuàng)建和Java層的也完全不一樣,它利用了Linux的epoll機制檢測了Input的fd和喚醒fd硬萍。從功能上來講扩所,這個喚醒fd才是真正處理Java Message和Native Message的鑰匙。
PS:5.0以上的版本Loooer定義在System/core下
上面說了半天朴乖,那我們就來看下Native的Looper的構(gòu)造函數(shù)
3祖屏、 Native層的Looper的構(gòu)造函數(shù)
代碼在Looper.cpp 71行
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
/** 這才是Linux后來才有的東西,負責線程通信寒砖,替換了老版本的pipe */
//構(gòu)造喚醒時間的fd
mWakeEventFd = eventfd(0, EFD_NONBLOCK);
AutoMutex _l(mLock);
rebuildEpollLocked();
}
這個方法重點就是調(diào)用了rebuildEpollLocked(); 函數(shù)
PS:這里說一下eventfd赐劣,event具體與pipe有點像,用來完成兩個線程之間(現(xiàn)在也支持進程級別)哩都,能夠用來作為線程之間通訊魁兼,類似于pthread_cond_t。
4、 Looper::rebuildEpollLocked() 函數(shù)
代碼在Looper.cpp 140行
void Looper::rebuildEpollLocked() {
// Close old epoll instance if we have one.
if (mEpollFd >= 0) {
#if DEBUG_CALLBACKS
ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
#endif
// 關(guān)閉老的epoll實例
close(mEpollFd);
}
// Allocate the new epoll instance and register the wake pipe.
// 創(chuàng)建一個epoll實例咐汞,并注冊wake管道盖呼。
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
struct epoll_event eventItem;
// 清空,把未使用的數(shù)據(jù)區(qū)域進行置0操作
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
//關(guān)注EPOLLIN事件化撕,也就是可讀
eventItem.events = EPOLLIN;
//設(shè)置Fd
eventItem.data.fd = mWakeEventFd;
//將喚醒事件(mWakeEventFd)添加到epoll實例(mEpollFd)几晤,其實只是為epoll放置一個喚醒機制
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance. errno=%d",
errno);
// 這里主要添加的是Input事件,如鍵盤植阴、傳感器輸入蟹瘾,這里基本上是由系統(tǒng)負責。
for (size_t i = 0; i < mRequests.size(); i++) {
const Request& request = mRequests.valueAt(i);
struct epoll_event eventItem;
request.initEventItem(&eventItem);
// 將request的隊列事件掠手,分別添加到epoll實例
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, errno=%d",
request.fd, errno);
}
}
這里一定要明白的是憾朴,添加這些fd除了mWakeEventFd負責解除阻塞讓程序繼續(xù)運行,從而處理Native Message和Java Message外喷鸽,其他fd與Message的處理其實毫無關(guān)系众雷。此時Java層與Native聯(lián)系如下:
這時候大家可能有點蒙,所以我下面補充1個知識點做祝,希望能幫助大家
8砾省、 小結(jié)
所有整個流程整理如下圖:
(二) nativeDestroy()
nativeDestroy是在MessageQueue的dispose()方法中調(diào)用,主要用于清空回收
代碼在MessageQueue.java 84行
// Disposes of the underlying message queue.
// Must only be called on the looper thread or the finalizer.
private void dispose() {
if (mPtr != 0) {
// native方法
nativeDestroy(mPtr);
mPtr = 0;
}
}
根據(jù)Android跨進程通信IPC之3——關(guān)于"JNI"的那些事中知道混槐,nativeDestroy()這個native方法對應(yīng)的是android_os_MessageQueue.cpp里面的android_os_MessageQueue_nativeDestroy()函數(shù)
1编兄、android_os_MessageQueue_nativeDestroy()函數(shù)
代碼在MessageQueue.java 183行
static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
// 強制類型轉(zhuǎn)換為nativeMessageQueue
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
//調(diào)用nativeMessageQueue的decStrong()函數(shù)
nativeMessageQueue->decStrong(env);
}
我們看到上面代碼是
- 首先,將Java層傳遞下來的mPtr轉(zhuǎn)換為nativeMessageQueue
- 其次声登,nativeMessageQueue調(diào)用decStrong(env)
nativeMessageQueue繼承自RefBase類翻诉,所以decStrong最終調(diào)用的是RefBase.decStrong()。
Android跨進程通信IPC之4——AndroidIPC基礎(chǔ)2的第五部分五捌刮、智能指針碰煌,中對智能指針有詳細描述,這里就不過多介紹了
2绅作、總體流程圖
(三) nativePollOnce()
nativePollOnce()是在MessageQueue的next()方法中調(diào)用芦圾,用于提取消息的調(diào)用鏈
代碼在MessageQueue.java 323行
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
for (;;) {
...
//阻塞操作
nativePollOnce(ptr, nextPollTimeoutMillis);
...
}
根據(jù)Android跨進程通信IPC之3——關(guān)于"JNI"的那些事中知道,nativeDestroy()這個native方法對應(yīng)的是android_os_MessageQueue.cpp里面的android_os_MessageQueue_nativePollOnce()函數(shù)
1俄认、nativePollOnce()
代碼在MessageQueue.java 188行
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis) {
//將Java層傳遞下來的mPtr轉(zhuǎn)換為nativeMessageQueue
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
我們看到上面代碼是
- 首先个少,將Java層傳遞下來的mPtr轉(zhuǎn)換為nativeMessageQueue
- 其次,nativeMessageQueue調(diào)用pollOnce(env, obj, timeoutMillis)
那我們就來看下pollOnce(env, obj, timeoutMillis)方法
2眯杏、 NativeMessageQueue::pollOnce(JNIEnv*, jobject, int)函數(shù)
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
mPollEnv = env;
mPollObj = pollObj;
// 重點函數(shù)
mLooper->pollOnce(timeoutMillis);
mPollObj = NULL;
mPollEnv = NULL;
if (mExceptionObj) {
env->Throw(mExceptionObj);
env->DeleteLocalRef(mExceptionObj);
mExceptionObj = NULL;
}
}
這個函數(shù)內(nèi)容很簡答夜焦, 主要就是進行賦值,并調(diào)用pollOnce(timeoutMillis)
那我們再來看一下pollOnce(timeoutMillis)函數(shù)
3岂贩、Looper::pollOnce()函數(shù)
代碼在Looper.h 264 行
inline int pollOnce(int timeoutMillis) {
return pollOnce(timeoutMillis, NULL, NULL, NULL);
}
這個函數(shù)里面主要是調(diào)用的是ollOnce(timeoutMillis, NULL, NULL, NULL);
4茫经、Looper::pollOnce(int, int, int, void**)函數(shù)
代碼在Looper.cpp 264 行
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
// 對fd對應(yīng)的Responses進行處理,后面發(fā)現(xiàn)Response里都是活動fd
for (;;) {
// 先處理沒有Callback的Response事件
while (mResponseIndex < mResponses.size()) {
const Response& response = mResponses.itemAt(mResponseIndex++);
int ident = response.request.ident;
if (ident >= 0) {
// ident>=0則表示沒有callback,因為POLL_CALLBACK=-2
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - returning signalled identifier %d: "
"fd=%d, events=0x%x, data=%p",
this, ident, fd, events, data);
#endif
if (outFd != NULL) *outFd = fd;
if (outEvents != NULL) *outEvents = events;
if (outData != NULL) *outData = data;
return ident;
}
}
// 注意這里處于循環(huán)內(nèi)部卸伞,改變result的值在后面的pollInner
if (result != 0) {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
if (outFd != NULL) *outFd = 0;
if (outEvents != NULL) *outEvents = 0;
if (outData != NULL) *outData = NULL;
return result;
}
// 再處理內(nèi)部輪訓
result = pollInner(timeoutMillis);
}
}
參數(shù)說明:
- timeoutMillis:超時時長
- outFd:發(fā)生事件的文件描述符
- outEvents:當前outFd上發(fā)生的事件抹镊,包含以下4類事件
- EVENT_INPUT:可讀
- EVENT_OUTPUT:可寫
- EVENT_ERROR:錯誤
- EVENT_HANGUP:中斷
- outData:上下文數(shù)據(jù)
這個函數(shù)內(nèi)部最后調(diào)用了pollInner(int),讓我們來看一下
5荤傲、Looper::pollInner()函數(shù)
代碼在Looper.cpp 220 行
int Looper::pollInner(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif
// Adjust the timeout based on when the next message is due.
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;
}
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - next message in %" PRId64 "ns, adjusted timeout: timeoutMillis=%d",
this, mNextMessageUptime - now, timeoutMillis);
#endif
}
// Poll.
int result = POLL_WAKE;
mResponses.clear();
mResponseIndex = 0;
// We are about to idle.
// 即將處于idle狀態(tài)
mPolling = true;
// fd最大的個數(shù)是16
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
// 等待時間發(fā)生或者超時垮耳,在nativeWake()方法,向管道寫端寫入字符遂黍,則方法會返回终佛。
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
// No longer idling.
// 不再處于idle狀態(tài)
mPolling = false;
// 請求鎖 ,因為在Native Message的處理和添加邏輯上需要同步
// Acquire lock.
mLock.lock();
// Rebuild epoll set if needed.
// 如果需要雾家,重建epoll
if (mEpollRebuildRequired) {
mEpollRebuildRequired = false;
// epoll重建查蓉,直接跳轉(zhuǎn)到Done
rebuildEpollLocked();
goto Done;
}
// Check for poll error.
if (eventCount < 0) {
if (errno == EINTR) {
goto Done;
}
ALOGW("Poll failed with an unexpected error, errno=%d", errno);
// epoll事件個數(shù)小于0,發(fā)生錯誤榜贴,直接跳轉(zhuǎn)Done
result = POLL_ERROR;
goto Done;
}
// Check for poll timeout.
//如果需要,重建epoll
if (eventCount == 0) {
//epoll事件個數(shù)等于0妹田,發(fā)生超時唬党,直接跳轉(zhuǎn)Done
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - timeout", this);
#endif
result = POLL_TIMEOUT;
goto Done;
}
// Handle all events.
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
#endif
// 循環(huán)處理所有的事件
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
//首先處理mWakeEventFd
if (fd == mWakeEventFd) {
//如果是喚醒mWakeEventFd有反應(yīng)
if (epollEvents & EPOLLIN) {
/**重點代碼*/
// 已經(jīng)喚醒了,則讀取并清空管道數(shù)據(jù)
awoken(); // 該函數(shù)內(nèi)部就是read鬼佣,從而使FD可讀狀態(tài)被清除
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
}
} else {
// 其他input fd處理驶拱,其實就是將活動放入response隊列,等待處理
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;
// 處理request晶衷,生成對應(yīng)的response對象蓝纲,push到響應(yīng)數(shù)組
pushResponse(events, mRequests.valueAt(requestIndex));
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
"no longer registered.", epollEvents, fd);
}
}
}
Done: ;
// Invoke pending message callbacks.
// 再處理Native的Message,調(diào)用相應(yīng)回調(diào)方法
mNextMessageUptime = LLONG_MAX;
while (mMessageEnvelopes.size() != 0) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
if (messageEnvelope.uptime <= now) {
// Remove the envelope from the list.
// We keep a strong reference to the handler until the call to handleMessage
// finishes. Then we drop it so that the handler can be deleted *before*
// we reacquire our lock.
{ // obtain handler
sp<MessageHandler> handler = messageEnvelope.handler;
Message message = messageEnvelope.message;
mMessageEnvelopes.removeAt(0);
mSendingMessage = true;
// 釋放鎖
mLock.unlock();
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
ALOGD("%p ~ pollOnce - sending message: handler=%p, what=%d",
this, handler.get(), message.what);
#endif
// 處理消息事件
handler->handleMessage(message);
} // release handler
// 請求鎖
mLock.lock();
mSendingMessage = false;
// 發(fā)生回調(diào)
result = POLL_CALLBACK;
} else {
// The last message left at the head of the queue determines the next wakeup time.
mNextMessageUptime = messageEnvelope.uptime;
break;
}
}
// Release lock.
// 釋放鎖
mLock.unlock();
// Invoke all response callbacks.
// 處理帶有Callback()方法的response事件晌纫,執(zhí)行Response相應(yīng)的回調(diào)方法
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;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
this, response.request.callback.get(), fd, events, data);
#endif
// 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.
// 處理請求的回調(diào)方法
int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
// 移除fd
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引用的回調(diào)方法
response.request.callback.clear();
// 發(fā)生回調(diào)
result = POLL_CALLBACK;
}
}
return result;
}
pollOnce返回值說明:
- POLL_WAKE: 表示由wake()出發(fā)税迷,即pipe寫端的write事件觸發(fā)
- POLL_CALLBACK:表示某個被監(jiān)聽fd被觸發(fā)
- POLL_TIMEOUT:表示等待超時
- POLL_ERROR:表示等待期間發(fā)生錯誤
pollInner()方法的處理流程:
- 1、先調(diào)用epoll_wait()锹漱,這是阻塞方法箭养,用于等待事件發(fā)生或者超時。
- 2哥牍、對于epoll_wait()返回毕泌,當且僅當以下3種情況出現(xiàn)
- POLL_ERROR:發(fā)生錯誤,直接跳轉(zhuǎn)Done
- POLL_TIMEOUT:發(fā)生超時嗅辣,直接跳轉(zhuǎn)到Done
- 檢測到管道有事情發(fā)生撼泛,則再根據(jù)情況做相應(yīng)處理:
- 如果檢測到管道產(chǎn)生事件,則直接讀取管道的數(shù)據(jù)
- 如果是其他事件澡谭,則處理request愿题,生成對應(yīng)的response對象,push到response數(shù)組
- 3、進入Done標記位的代碼:
- 先處理Native的Message抠忘,調(diào)用Native的Handler來處理該Message
- 再處理Resposne數(shù)組撩炊,POLL_CALLBACK類型的事件
從上面的流程,可以發(fā)現(xiàn)對于Request先收集崎脉,一并放入response數(shù)組拧咳,而不是馬上執(zhí)行。真正在Done開始執(zhí)行的時候囚灼,先處理Native Message骆膝,再處理Request,說明Native Message優(yōu)先級高于Request請求的優(yōu)先級灶体。
PS:在polOnce()方法中阅签,先處理Response數(shù)組不帶Callback的事件,再調(diào)用了再調(diào)用了pollInner()函數(shù)蝎抽。
6政钟、Looper::awoken()函數(shù)
代碼在Looper.cpp 418行
void Looper::awoken() {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ awoken", this);
#endif
uint64_t counter;
// 不斷的讀取管道數(shù)據(jù),目的就是為了清空管道內(nèi)容
TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
}
7樟结、小結(jié)
整體的流程圖如下:
(四)养交、nativeDestroy()
nativeWake用于喚醒功能,在添加消息到消息隊列enqueueMessage()瓢宦,或者把消息從消息隊列中全部移除quit()碎连,再有需要時會調(diào)用nativeWake方法。包含喚醒過程的添加消息的調(diào)用鏈
下面來進一步來看看調(diào)用鏈的過程:
1驮履、enqueueMessage(Message, long)
代碼在MessageQueue.java 533行
boolean enqueueMessage(Message msg, long when) {
....
//將Message按按時間插入MessageQueue
if (needWake) {
nativeWake(mPtr);
}
....
}
在向消息隊列添加Message時鱼辙,需要根據(jù)mBlocked情況來就決定是否需要調(diào)用nativeWake。
根據(jù)Android跨進程通信IPC之3——關(guān)于"JNI"的那些事中知道玫镐,nativeDestroy()這個native方法對應(yīng)的是android_os_MessageQueue.cpp里面的android_os_MessageQueue_nativeWake(JNIEnv*, jclass, jlong ) 函數(shù)
2倒戏、android_os_MessageQueue_nativeWake()
代碼在android_os_MessageQueue.cpp 194行
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
// 將Java層傳遞下來的mPtr轉(zhuǎn)換為nativeMessageQueue
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
//調(diào)用wake函數(shù)
nativeMessageQueue->wake();
}
我們看到上面代碼是
- 首先,將Java層傳遞下來的mPtr轉(zhuǎn)換為nativeMessageQueue
- 其次恐似,nativeMessageQueue調(diào)用wake()函數(shù)
3峭梳、NativeMessageQueue::wake()函數(shù)
代碼在android_os_MessageQueue.cpp 121行
void NativeMessageQueue::wake() {
mLooper->wake();
}
這個方法很簡單,就是直接調(diào)用Looper的wake()函數(shù)蹂喻,
4葱椭、Looper::wake()函數(shù)
代碼在Looper.cpp 404行
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ wake", this);
#endif
uint64_t inc = 1;
// 向管道m(xù)WakeEventFd寫入字符1
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
ALOGW("Could not write wake signal, errno=%d", errno);
}
}
}
Looper類的 wake()函數(shù)只是往mWakeEventfd中寫了一些內(nèi)容,這個fd只是通知而已口四,類似于pipi孵运,最后會把epoll_wai喚醒,線程就不阻塞了繼續(xù)發(fā)送
Native層的消息蔓彩,然后處理之前的addFd事件治笨,然后處理Java層的消息驳概。
PS:其中TEMP_FAILURE_RETRY 是一個宏定義,當執(zhí)行write失敗后旷赖,會不斷重復執(zhí)行顺又,直到執(zhí)行成功為止。
5等孵、小結(jié)
總結(jié)一下流程圖如下:
(五)稚照、sendMessage()
前面幾篇文章講述了Java層如何向MessageQueue類添加消息,那么接下來講講Native層如何向MessageQueue發(fā)送消息俯萌。
1果录、Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) 函數(shù)
代碼在Looper.cpp 583行
void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
sendMessageAtTime(now, handler, message);
}
我們看到方法里面調(diào)用了sendMessageAtTime(now, handler, message) 函數(shù)
2、 Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
const Message& message)函數(shù)
代碼在Looper.cpp 588行
void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
const Message& message) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
sendMessageAtTime(now + uptimeDelay, handler, message);
}
我們看到方法里面調(diào)用了sendMessageAtTime(now, handler, message) 函數(shù)
所以我們說:
sendMessage()和sendMessageDelayed()都是調(diào)用sendMessageAtTime()來完成消息插入咐熙。
那我們就來看一下sendMessageAtTime()
3弱恒、 Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
const Message& message)函數(shù)
void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
const Message& message) {
#if DEBUG_CALLBACKS
ALOGD("%p ~ sendMessageAtTime - uptime=%" PRId64 ", handler=%p, what=%d",
this, uptime, handler.get(), message.what);
#endif
size_t i = 0;
{ // acquire lock
// 請求鎖
AutoMutex _l(mLock);
size_t messageCount = mMessageEnvelopes.size();
// 找到message應(yīng)該插入的位置i
while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
i += 1;
}
MessageEnvelope messageEnvelope(uptime, handler, message);
mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
// Optimization: If the Looper is currently sending a message, then we can skip
// the call to wake() because the next thing the Looper will do after processing
// messages is to decide when the next wakeup time should be. In fact, it does
// not even matter whether this code is running on the Looper thread.
// 如果當前正在發(fā)送消息,那么不再調(diào)用wake()棋恼,直接返回
if (mSendingMessage) {
return;
}
} // release lock
// 釋放鎖
// Wake the poll loop only when we enqueue a new message at the head.
// 當消息加入到消息隊列的頭部時返弹,需要喚醒poll循環(huán)
if (i == 0) {
wake();
}
}
(六)、sendMessage()
本節(jié)介紹了MessageQueue的native()方法爪飘,經(jīng)過層層調(diào)用:
- nativeInit()方法义起,最終實現(xiàn)由epoll機制中的epoll_create()/epoll_ctl()完成
- nativeDestory()方法,最終實現(xiàn)由RefBase::decStrong()完成
- nativePollOnce()方法悦施,最終實現(xiàn)由Looper::pollOnce()完成
- nativeWake()方法,最終實現(xiàn)由Looper::wake()調(diào)用write方法去团,向管道寫入字符
- nativeIsPolling()抡诞,nativeSetFileDescriptorEvents()這兩個方法類似,此處就不一一列舉了土陪。
三昼汗、Native結(jié)構(gòu)體和類
Looper.h/Looper.cpp文件中定義了Message結(jié)構(gòu)體,消息處理類鬼雀,回調(diào)類顷窒,Looper類
(一)、Message結(jié)構(gòu)體
代碼在(http://androidxref.com/6.0.1_r10/xref/system/core/include/utils/Looper.h) 50行
struct Message {
Message() : what(0) { }
Message(int what) : what(what) { }
/* The message type. (interpretation is left up to the handler) */
// 消息類型
int what;
};
(二)源哩、消息處理類
1鞋吉、MessageHandler類
代碼在Looper.h 67行
/**
* Interface for a Looper message handler.
*
* The Looper holds a strong reference to the message handler whenever it has
* a message to deliver to it. Make sure to call Looper::removeMessages
* to remove any pending messages destined for the handler so that the handler
* can be destroyed.
*/
class MessageHandler : public virtual RefBase {
protected:
virtual ~MessageHandler() { }
public:
/**
* Handles a message.
*/
virtual void handleMessage(const Message& message) = 0;
};
這個類很簡單,就不多說了励烦,這里說下注釋:
- 處理Looper消息程序的接口谓着。
- 當一個消息要傳遞給其對應(yīng)的Handler時候,Looper持有一個消息Handler的強引用坛掠。在這個Handler銷毀之前赊锚,請確保調(diào)用Looper :: removeMessages來刪除待處理的消息治筒。
2、WeakMessageHandler類
代碼在Looper.h 82行
/**
* A simple proxy that holds a weak reference to a message handler.
*/
class WeakMessageHandler : public MessageHandler {
protected:
virtual ~WeakMessageHandler();
public:
WeakMessageHandler(const wp<MessageHandler>& handler);
virtual void handleMessage(const Message& message);
private:
wp<MessageHandler> mHandler;
};
這里并沒有handleMessage的代碼舷蒲,我們是不是忽略了什么耸袜?再找一下,果然這塊的代碼在
Looper.cpp 38行
void WeakMessageHandler::handleMessage(const Message& message) {
sp<MessageHandler> handler = mHandler.promote();
if (handler != NULL) {
調(diào)用Mes
handler->handleMessage(message);
}
}
(三)牲平、回調(diào)類
1堤框、LooperCallback類
代碼在Looper.h 98行
/**
* A looper callback.
*/
class LooperCallback : public virtual RefBase {
protected:
virtual ~LooperCallback() { }
public:
/**
* Handles a poll event for the given file descriptor.
* It is given the file descriptor it is associated with,
* a bitmask of the poll events that were triggered (typically EVENT_INPUT),
* and the data pointer that was originally supplied.
*
* Implementations should return 1 to continue receiving callbacks, or 0
* to have this file descriptor and callback unregistered from the looper.
*/
// 用于處理指定的文件描述符poll事件
virtual int handleEvent(int fd, int events, void* data) = 0;
};
簡單翻譯一下handleEvent方法的注釋:
- 處理給定文件描述符的輪訓事件。
- 用來 將 最初提供的數(shù)據(jù)指針和輪訓事件的掩碼(通常為EVENT_INPUT)來關(guān)聯(lián)的文件描述符欠拾。
- 實現(xiàn)子類如果想繼續(xù)接收回調(diào)則返回1胰锌,如果未注冊文件描述符和回調(diào)則返回0
2、SimpleLooperCallback類
代碼在Looper.cpp 118行
class SimpleLooperCallback : public LooperCallback {
protected:
virtual ~SimpleLooperCallback();
public:
SimpleLooperCallback(Looper_callbackFunc callback);
virtual int handleEvent(int fd, int events, void* data);
private:
Looper_callbackFunc mCallback;
};
它和WeakMessageHandler類一樣handleEvent的方法在Looper.cpp 55行
int SimpleLooperCallback::handleEvent(int fd, int events, void* data) {
// 調(diào)用回調(diào)方法
return mCallback(fd, events, data);
}
(四)藐窄、Looper類
1 资昧、 Native層的Looper類簡介
2 、 Native層的Looper類常量
// 每個epoll實例默認的文件描述符個數(shù)
static const int EPOLL_SIZE_HINT = 8;
// 輪訓事件的文件描述符個數(shù)上限
static const int EPOLL_MAX_EVENTS = 16;
3荆忍、Native Looper類的常用方法:
方法 | 解釋 |
---|---|
Looper(bool) | Looper的構(gòu)造函數(shù) |
static sp<Looper> prepar(int) | 如果該線程沒有綁定Looper格带,才創(chuàng)建Loopr,否則直接返回 |
int pollOnec(int ,int* int,void) | 輪訓刹枉,等待事件發(fā)生 |
void wake() | 喚醒Looper |
void sendMessage(const sp<MessageHandler>&handler,const Message&message) | 發(fā)送消息 |
int addFd(int,int,int,Looper_callbackFunc,void*) | 添加要監(jiān)聽的文件描述符fd |
4叽唱、Request、Resposne微宝、MessageEvent 三個結(jié)構(gòu)體
Looper類的內(nèi)部定義了Request棺亭、Resposne、MessageEnvelope這三個結(jié)構(gòu)體
關(guān)系圖如下:
4.1蟋软、Request 結(jié)構(gòu)體
代碼在Looper.h 420行
// 請求結(jié)構(gòu)體
struct Request {
int fd;
int ident;
int events;
int seq;
sp<LooperCallback> callback;
void* data;
void initEventItem(struct epoll_event* eventItem) const;
};
4.2镶摘、Resposne 結(jié)構(gòu)體
代碼在Looper.h 431行
// 響應(yīng)結(jié)構(gòu)體
struct Response {
int events;
Request request;
};
4.3、MessageEnvelope 結(jié)構(gòu)體
代碼在Looper.h 436行
// 信封結(jié)構(gòu)體
struct MessageEnvelope {
MessageEnvelope() : uptime(0) { }
MessageEnvelope(nsecs_t uptime, const sp<MessageHandler> handler,
const Message& message) : uptime(uptime), handler(handler), message(message) {
}
nsecs_t uptime;
sp<MessageHandler> handler;
Message message;
};
MessageEnvelope正如其名字岳守,信封凄敢。MessageEnvelope里面記錄著收信人(handler),發(fā)信時間(uptime)湿痢,信件內(nèi)容(message)涝缝。
5、Native Looper類的類圖如下:
6 Native Looper的監(jiān)聽文件描述符
Native Looper除了提供message機制外譬重,還提供監(jiān)聽文件描述符的方式拒逮。通過addFd()接口加入需要被監(jiān)聽的文件描述符。
代碼在Looper.cpp 434行
int addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data);
int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data);
其中:
- fd:為所需要監(jiān)聽的文件描述符
- ident:表示為當前發(fā)生時間的標識符臀规,必須>=0,或者為POLL_CALLBACK(-2)如果指定了callback
- events:表示為要監(jiān)聽的文件類型消恍,默認是EVENT_INPUT。
- callback:當有事件發(fā)生時以现,會回調(diào)該callback函數(shù)狠怨。
- data:兩種使用方式:
- 指定callback來處理事件:當該文件描述符上有事件來時约啊,該callback會被執(zhí)行,然后從fd讀取數(shù)據(jù)佣赖。這個時候ident是被忽略的恰矩。
- 通過指定的ident來處理事件:當該文件描述符有數(shù)據(jù)來到時,pollOnce()會返回一個ident憎蛤,調(diào)用者會判斷該ident是否等于自己需要處理事件ident外傅,如果是的話,則開始處理事件俩檬。
(####) 五萎胰、Java層的addFd
我之前一直以為只能在C層的Looper中才能addFd,原來在Java層也通過JNI做了這個功能棚辽。我們可以在MessageQueue中的addOnFileDescriptorEventListener來實現(xiàn)這個功能技竟。
代碼在MessageQueue.java 186行
/**
* Adds a file descriptor listener to receive notification when file descriptor
* related events occur.
* <p>
* If the file descriptor has already been registered, the specified events
* and listener will replace any that were previously associated with it.
* It is not possible to set more than one listener per file descriptor.
* </p><p>
* It is important to always unregister the listener when the file descriptor
* is no longer of use.
* </p>
*
* @param fd The file descriptor for which a listener will be registered.
* @param events The set of events to receive: a combination of the
* {@link OnFileDescriptorEventListener#EVENT_INPUT},
* {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and
* {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks. If the requested
* set of events is zero, then the listener is unregistered.
* @param listener The listener to invoke when file descriptor events occur.
*
* @see OnFileDescriptorEventListener
* @see #removeOnFileDescriptorEventListener
*/
public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
@OnFileDescriptorEventListener.Events int events,
@NonNull OnFileDescriptorEventListener listener) {
if (fd == null) {
throw new IllegalArgumentException("fd must not be null");
}
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
synchronized (this) {
updateOnFileDescriptorEventListenerLocked(fd, events, listener);
}
}
通過上面代碼分析,我們知道這里面有兩個重點
- 1 onFileDescriptorEventListener 這個回調(diào)
- 2 updateOnFileDescriptorEventListenerLocked()方法
8.1屈藐、OnFileDescriptorEventListener
代碼在MessageQueue.java 186行
/**
* A listener which is invoked when file descriptor related events occur.
*/
public interface OnFileDescriptorEventListener {
/**
* File descriptor event: Indicates that the file descriptor is ready for input
* operations, such as reading.
* <p>
* The listener should read all available data from the file descriptor
* then return <code>true</code> to keep the listener active or <code>false</code>
* to remove the listener.
* </p><p>
* In the case of a socket, this event may be generated to indicate
* that there is at least one incoming connection that the listener
* should accept.
* </p><p>
* This event will only be generated if the {@link #EVENT_INPUT} event mask was
* specified when the listener was added.
* </p>
*/
public static final int EVENT_INPUT = 1 << 0;
/**
* File descriptor event: Indicates that the file descriptor is ready for output
* operations, such as writing.
* <p>
* The listener should write as much data as it needs. If it could not
* write everything at once, then it should return <code>true</code> to
* keep the listener active. Otherwise, it should return <code>false</code>
* to remove the listener then re-register it later when it needs to write
* something else.
* </p><p>
* This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
* specified when the listener was added.
* </p>
*/
public static final int EVENT_OUTPUT = 1 << 1;
/**
* File descriptor event: Indicates that the file descriptor encountered a
* fatal error.
* <p>
* File descriptor errors can occur for various reasons. One common error
* is when the remote peer of a socket or pipe closes its end of the connection.
* </p><p>
* This event may be generated at any time regardless of whether the
* {@link #EVENT_ERROR} event mask was specified when the listener was added.
* </p>
*/
public static final int EVENT_ERROR = 1 << 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag=true, value={EVENT_INPUT, EVENT_OUTPUT, EVENT_ERROR})
public @interface Events {}
/**
* Called when a file descriptor receives events.
*
* @param fd The file descriptor.
* @param events The set of events that occurred: a combination of the
* {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
* @return The new set of events to watch, or 0 to unregister the listener.
*
* @see #EVENT_INPUT
* @see #EVENT_OUTPUT
* @see #EVENT_ERROR
*/
@Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
}
private static final class FileDescriptorRecord {
public final FileDescriptor mDescriptor;
public int mEvents;
public OnFileDescriptorEventListener mListener;
public int mSeq;
public FileDescriptorRecord(FileDescriptor descriptor,
int events, OnFileDescriptorEventListener listener) {
mDescriptor = descriptor;
mEvents = events;
mListener = listener;
}
}
8.2榔组、updateOnFileDescriptorEventListenerLocked()方法
代碼在MessageQueue.java 222行
private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
OnFileDescriptorEventListener listener) {
final int fdNum = fd.getInt$();
int index = -1;
FileDescriptorRecord record = null;
if (mFileDescriptorRecords != null) {
index = mFileDescriptorRecords.indexOfKey(fdNum);
if (index >= 0) {
record = mFileDescriptorRecords.valueAt(index);
if (record != null && record.mEvents == events) {
return;
}
}
}
if (events != 0) {
events |= OnFileDescriptorEventListener.EVENT_ERROR;
if (record == null) {
if (mFileDescriptorRecords == null) {
mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
}
//fd保存在FileDescriptorRecord對象
record = new FileDescriptorRecord(fd, events, listener);
// mFileDescriptorRecords 保存
mFileDescriptorRecords.put(fdNum, record);
} else {
record.mListener = listener;
record.mEvents = events;
record.mSeq += 1;
}
// 調(diào)用native函數(shù)
nativeSetFileDescriptorEvents(mPtr, fdNum, events);
} else if (record != null) {
record.mEvents = 0;
mFileDescriptorRecords.removeAt(index);
}
}
8.2.1、android_os_MessageQueue_nativeSetFileDescriptorEvents()函數(shù)
根據(jù)Android跨進程通信IPC之3——關(guān)于"JNI"的那些事中知道联逻,nativeInit這個native方法對應(yīng)的是android_os_MessageQueue.cpp里面的android_os_MessageQueue_nativeSetFileDescriptorEvents(JNIEnv* env, jclass clazz, jlong ptr, jint fd, jint events)函數(shù)
代碼在android_os_MessageQueue.cpp 204行
static void android_os_MessageQueue_nativeSetFileDescriptorEvents(JNIEnv* env, jclass clazz,
jlong ptr, jint fd, jint events) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->setFileDescriptorEvents(fd, events);
}
我們看到這個函數(shù)里面調(diào)用了nativeMessageQueue的setFileDescriptorEvents(fd, events);函數(shù)搓扯。
8.2.2、NativeMessageQueue::setFileDescriptorEvents(int fd, int events)函數(shù)
代碼在android_os_MessageQueue.cpp 125行
void NativeMessageQueue::setFileDescriptorEvents(int fd, int events) {
if (events) {
int looperEvents = 0;
if (events & CALLBACK_EVENT_INPUT) {
looperEvents |= Looper::EVENT_INPUT;
}
if (events & CALLBACK_EVENT_OUTPUT) {
looperEvents |= Looper::EVENT_OUTPUT;
}
// 重點代碼
mLooper->addFd(fd, Looper::POLL_CALLBACK, looperEvents, this,
reinterpret_cast<void*>(events));
} else {
mLooper->removeFd(fd);
}
}
我們看到了在這個函數(shù)內(nèi)部調(diào)用了mLooper的addFd函數(shù)包归。
大家注意一下Looper的addFd函數(shù)锨推,中的倒數(shù)二個參數(shù)是this,側(cè)面說明了NativeMessageQueue繼承了LooperCallback公壤。
代碼在android_os_MessageQueue.cpp 41行
class NativeMessageQueue : public MessageQueue, public LooperCallback {
public:
NativeMessageQueue();
virtual ~NativeMessageQueue();
virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj);
void pollOnce(JNIEnv* env, jobject obj, int timeoutMillis);
void wake();
void setFileDescriptorEvents(int fd, int events);
virtual int handleEvent(int fd, int events, void* data);
...
}
所以說换可,需要實現(xiàn)handleEvent()函數(shù)。handleEvent()函數(shù)就是在looper中epoll_wait之后境钟,當我們增加的fd有數(shù)據(jù)就會調(diào)用這個函數(shù)锦担。
代碼在android_os_MessageQueue.cpp 141行
int NativeMessageQueue::handleEvent(int fd, int looperEvents, void* data) {
int events = 0;
if (looperEvents & Looper::EVENT_INPUT) {
events |= CALLBACK_EVENT_INPUT;
}
if (looperEvents & Looper::EVENT_OUTPUT) {
events |= CALLBACK_EVENT_OUTPUT;
}
if (looperEvents & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP | Looper::EVENT_INVALID)) {
events |= CALLBACK_EVENT_ERROR;
}
int oldWatchedEvents = reinterpret_cast<intptr_t>(data);
// 調(diào)用回調(diào)
int newWatchedEvents = mPollEnv->CallIntMethod(mPollObj,
gMessageQueueClassInfo.dispatchEvents, fd, events); /
if (!newWatchedEvents) {
return 0; // unregister the fd
}
if (newWatchedEvents != oldWatchedEvents) {
setFileDescriptorEvents(fd, newWatchedEvents);
}
return 1;
}
最后在java的MessageQueue中的dispatchEvent就是在jni層反調(diào)過來的俭识,然后調(diào)用之前注冊的回調(diào)函數(shù)
代碼在MessageQueue.java259行
// Called from native code.
private int dispatchEvents(int fd, int events) {
// Get the file descriptor record and any state that might change.
final FileDescriptorRecord record;
final int oldWatchedEvents;
final OnFileDescriptorEventListener listener;
final int seq;
synchronized (this) {
record = mFileDescriptorRecords.get(fd);
if (record == null) {
return 0; // spurious, no listener registered
}
oldWatchedEvents = record.mEvents;
events &= oldWatchedEvents; // filter events based on current watched set
if (events == 0) {
return oldWatchedEvents; // spurious, watched events changed
}
listener = record.mListener;
seq = record.mSeq;
}
// Invoke the listener outside of the lock.
int newWatchedEvents = listener.onFileDescriptorEvents(
record.mDescriptor, events);
if (newWatchedEvents != 0) {
newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
}
// Update the file descriptor record if the listener changed the set of
// events to watch and the listener itself hasn't been updated since.
if (newWatchedEvents != oldWatchedEvents) {
synchronized (this) {
int index = mFileDescriptorRecords.indexOfKey(fd);
if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
&& record.mSeq == seq) {
record.mEvents = newWatchedEvents;
if (newWatchedEvents == 0) {
mFileDescriptorRecords.removeAt(index);
}
}
}
}
// Return the new set of events to watch for native code to take care of.
return newWatchedEvents;
}
四慨削、總結(jié)
(一)、Native與Java的對應(yīng)關(guān)系
MessageQueue通過mPtr變量保存了NativeMessageQueue對象套媚,從而使得MessageQueue成為Java層和Native層的樞紐缚态,既能處理上層消息,也能處理Native消息堤瘤,下圖列舉了Java層與Native層的對應(yīng)圖
圖解:
- 1玫芦、紅色虛線關(guān)系:Java層和Native層的MessageQueue通過JNI建立關(guān)聯(lián),彼此之間能相互調(diào)用本辐,搞明白這個互調(diào)關(guān)系桥帆,也就搞明白Java如何調(diào)用C++代碼医增,C++代碼如何調(diào)用Java代碼
- 2、藍色虛線關(guān)系:Handler/Looper/Message這三大類Java層與Native層并沒有任何真正的關(guān)系老虫,只是分別在Java層和Native層的handler消息模型中具有相似的功能叶骨。都是彼此獨立的,各自實現(xiàn)相應(yīng)的邏輯祈匙。
- 3忽刽、WeakMessageHandler繼承與MessageHandler類,NativeMessageQueue繼承于MessageQueue類夺欲。
另外跪帝,消息處理流程是先處理NativeMessage,再處理Native Request些阅,最后處理Java Message伞剑。理解了該流程也就明白了有時上層消息很少,但響應(yīng)時間卻比較長的真正原因扑眉。
(二)纸泄、Native的流程
整體流程如下:
四 總結(jié)
Handler機制中Native的實現(xiàn)主要涉及了兩個類
- 1、NativeMessageQueue:在MessageQueue.java的構(gòu)造函數(shù)中腰素,調(diào)用了nativeInit創(chuàng)建了NativeMessageQueue對象聘裁,并且把指針變量返回給Java層的mPtr。而在NativeMessageQueue的構(gòu)造函數(shù)中弓千,會在當前線程中創(chuàng)建C++的Looper對象衡便。
- 2、Looper:控制eventfd的讀寫洋访,通過epoll監(jiān)聽eventfd的變化镣陕,來阻塞調(diào)用pollOnce和恢復調(diào)用wake當前線程
- 通過 epoll監(jiān)聽其他文件描述符的變化
- 通過 epoll處理C++層的消息機制,當調(diào)用Looper::sendMessageAtTime后姻政,調(diào)用wake觸發(fā)epoll
- Looper的構(gòu)造函數(shù)呆抑,創(chuàng)建一個eventfd(以前版本是pipe),eventfd它的主要用于進程或者線程間的通信汁展,然后創(chuàng)建epoll來監(jiān)聽該eventfd的變化
- Looper::pollOnce(int timeoutMillis) 內(nèi)部調(diào)用了pollInner鹊碍,再調(diào)用epoll_wait(mEpollFd, ..., timeoutMillis)阻塞timeoutMills時間,并監(jiān)聽文件描述符mEpollFd的變化食绿,當時間到了或者消息到了侈咕,即eventfd被寫入內(nèi)容后,從epoll_wait繼續(xù)往下執(zhí)行器紧,處理epoll_wait返回的消息耀销,該消息既有可能是eventfd產(chǎn)生的,也可能是其他文件描述符產(chǎn)生的铲汪。處理順序是,先處理普通的C++消息隊列mMessageEnvelopes,然后處理之前addFd的事件谒所,最后從pollOnce返回蝶俱,會繼續(xù)MessageQueue.java的next()函數(shù),取得Java層的消息來處理;
- Looper類的wake,函數(shù)只是往mWakeEventfd中寫了一些內(nèi)容,這個fd只是通知而已芦拿,類似pipe,最后會把epoll_wait喚醒查邢,線程就不阻塞了蔗崎,繼續(xù)先發(fā)送C層消息,然后處理之前addFd事件扰藕,然后處理Java層消息