【从源码看Android】03Android MessageQueue消息循环处理机制(epoll实现)

本文主要是介绍【从源码看Android】03Android MessageQueue消息循环处理机制(epoll实现),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 enqueueMessage


handler发送一条消息

[java]  view plain copy
  1. mHandler.sendEmptyMessage(1);  
经过层层调用,进入到sendMessageAtTime函数块,最后调用到enqueueMessage

Handler.java

[java]  view plain copy
  1. public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
  2.         MessageQueue queue = mQueue;  
  3.         if (queue == null) {  
  4.             RuntimeException e = new RuntimeException(  
  5.                     this + " sendMessageAtTime() called with no mQueue");  
  6.             Log.w("Looper", e.getMessage(), e);  
  7.             return false;  
  8.         }  
  9.         return enqueueMessage(queue, msg, uptimeMillis);  
  10.     }  


最后调用到Handler私有的函数enqueueMessage,把handler对象赋值给msg.target,调用queue.enqueueMessage

Handler.java
[java]  view plain copy
  1. private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
  2.         msg.target = this;  
  3.         if (mAsynchronous) {  
  4.             msg.setAsynchronous(true);  
  5.         }  
  6.         return queue.enqueueMessage(msg, uptimeMillis);  
  7.     }  


下面是核心代码,首先是获得同步锁,

MessageQueue.java

[java]  view plain copy
  1. boolean enqueueMessage(Message msg, long when) {  
  2.         if (msg.isInUse()) {  
  3.             throw new AndroidRuntimeException(msg + " This message is already in use.");  
  4.         }  
  5.         if (msg.target == null) {  
  6.             throw new AndroidRuntimeException("Message must have a target.");  
  7.         }  
  8.   
  9.         synchronized (this) {  
  10.             if (mQuitting) {  
  11.                 RuntimeException e = new RuntimeException(  
  12.                         msg.target + " sending message to a Handler on a dead thread");  
  13.                 Log.w("MessageQueue", e.getMessage(), e);  
  14.                 return false;  
  15.             }  
  16.   
  17.             msg.when = when;  
  18.             Message p = mMessages;  
  19.             boolean needWake;  
  20.             if (p == null || when == 0 || when < p.when) {  
  21.                 // New head, wake up the event queue if blocked.  
  22.                 msg.next = p;  
  23.                 mMessages = msg;  
  24.                 needWake = mBlocked;  
  25.             } else {  
  26.                 // Inserted within the middle of the queue.  Usually we don't have to wake  
  27.                 // up the event queue unless there is a barrier at the head of the queue  
  28.                 // and the message is the earliest asynchronous message in the queue.  
  29.                 needWake = mBlocked && p.target == null && msg.isAsynchronous();  
  30.                 Message prev;  
  31.                 for (;;) {  
  32.                     prev = p;  
  33.                     p = p.next;  
  34.                     if (p == null || when < p.when) {  
  35.                         break;  
  36.                     }  
  37.                     if (needWake && p.isAsynchronous()) {  
  38.                         needWake = false;  
  39.                     }  
  40.                 }  
  41.                 msg.next = p; // invariant: p == prev.next  
  42.                 prev.next = msg;  
  43.             }  
  44.   
  45.             // We can assume mPtr != 0 because mQuitting is false.  
  46.             if (needWake) {  
  47.                 nativeWake(mPtr);  
  48.             }  
  49.         }  
  50.         return true;  
  51.     }  

首先是获得自身的同步锁synchronized (this),接着这个msg跟MessageQueue实例的头结点Message进行触发时间先后的比较,

如果触发时间比现有的头结点Message前,则这个新的Message作为整个MessageQueue的头结点,如果阻塞着,则立即唤醒线程处理

如果触发时间比头结点晚,则按照触发时间先后,在消息队列中间插入这个结点

接着如果需要唤醒,则调用nativeWake函数


在android_os_MessageQueue.cpp里定义了nativeWake函数

[cpp]  view plain copy
  1. static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) {  
  2.     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);  
  3.     return nativeMessageQueue->wake();  
  4. }  

实际调用到mLooper->wake();

android_os_MessageQueue.cpp

[cpp]  view plain copy
  1. void NativeMessageQueue::wake() {  
  2.     mLooper->wake();  
  3. }  
而mLooper是cpp层的Looper对象,

framework/base/libs/utils/Looper.cpp

[cpp]  view plain copy
  1. void Looper::wake() {  
  2. #if DEBUG_POLL_AND_WAKE  
  3.     LOGD("%p ~ wake"this);  
  4. #endif  
  5.   
  6. #ifdef LOOPER_STATISTICS  
  7.     // FIXME: Possible race with awoken() but this code is for testing only and is rarely enabled.  
  8.     if (mPendingWakeCount++ == 0) {  
  9.         mPendingWakeTime = systemTime(SYSTEM_TIME_MONOTONIC);  
  10.     }  
  11. #endif  
  12.   
  13.     ssize_t nWrite;  
  14.     do {  
  15.         nWrite = write(mWakeWritePipeFd, "W", 1);  
  16.     } while (nWrite == -1 && errno == EINTR);  
  17.   
  18.     if (nWrite != 1) {  
  19.         if (errno != EAGAIN) {  
  20.             LOGW("Could not write wake signal, errno=%d", errno);  
  21.         }  
  22.     }  
  23. }  

是不是很熟悉?基本就是上一讲epoll原型的唤醒函数,向mWakeWritePipeFD写入1字节,唤醒监听block在mWakeReadPipeFD端口的epoll_wait



2 dequeueMessage


首先dequeueMessage只是我取的一个叫法,当java层的Looper进行loop的时候,就已经在不停地读取MessageQueue里的Message了

Looper.java

[java]  view plain copy
  1. public static void loop() {  
  2.         final Looper me = myLooper();  
  3.         if (me == null) {  
  4.             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");  
  5.         }  
  6.         final MessageQueue queue = me.mQueue;  
  7.   
  8.         // Make sure the identity of this thread is that of the local process,  
  9.         // and keep track of what that identity token actually is.  
  10.         Binder.clearCallingIdentity();  
  11.         final long ident = Binder.clearCallingIdentity();  
  12.   
  13.         for (;;) {  
  14.             Message msg = queue.next(); // might block  
  15.             if (msg == null) {  
  16.                 // No message indicates that the message queue is quitting.  
  17.                 return;  
  18.             }  
  19.   
  20.             // This must be in a local variable, in case a UI event sets the logger  
  21.             Printer logging = me.mLogging;  
  22.             if (logging != null) {  
  23.                 logging.println(">>>>> Dispatching to " + msg.target + " " +  
  24.                         msg.callback + ": " + msg.what);  
  25.             }  
  26.   
  27.             msg.target.dispatchMessage(msg);  
  28.   
  29.             if (logging != null) {  
  30.                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);  
  31.             }  
  32.   
  33.             // Make sure that during the course of dispatching the  
  34.             // identity of the thread wasn't corrupted.  
  35.             final long newIdent = Binder.clearCallingIdentity();  
  36.             if (ident != newIdent) {  
  37.                 Log.wtf(TAG, "Thread identity changed from 0x"  
  38.                         + Long.toHexString(ident) + " to 0x"  
  39.                         + Long.toHexString(newIdent) + " while dispatching to "  
  40.                         + msg.target.getClass().getName() + " "  
  41.                         + msg.callback + " what=" + msg.what);  
  42.             }  
  43.   
  44.             msg.recycle();  
  45.         }  
  46.     }  

调用queue.next()读取下一条消息(在loop调用的线程中),如果读取到了就msg,target.dispatchMessage,

下面来看看queue.next()如何实现


MessageQueue.java

[java]  view plain copy
  1. Message next() {  
  2.         int pendingIdleHandlerCount = -1// -1 only during first iteration  
  3.         int nextPollTimeoutMillis = 0;  
  4.         for (;;) {  
  5.             if (nextPollTimeoutMillis != 0) {  
  6.                 Binder.flushPendingCommands();  
  7.             }  
  8.   
  9.             // We can assume mPtr != 0 because the loop is obviously still running.  
  10.             // The looper will not call this method after the loop quits.  
  11.             nativePollOnce(mPtr, nextPollTimeoutMillis);  
  12.   
  13.             synchronized (this) {  
  14.                 // Try to retrieve the next message.  Return if found.  
  15.                 final long now = SystemClock.uptimeMillis();  
  16.                 Message prevMsg = null;  
  17.                 Message msg = mMessages;  
  18.                 if (msg != null && msg.target == null) {  
  19.                     // Stalled by a barrier.  Find the next asynchronous message in the queue.  
  20.                     do {  
  21.                         prevMsg = msg;  
  22.                         msg = msg.next;  
  23.                     } while (msg != null && !msg.isAsynchronous());  
  24.                 }  
  25.                 if (msg != null) {  
  26.                     if (now < msg.when) {  
  27.                         // Next message is not ready.  Set a timeout to wake up when it is ready.  
  28.                         nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);  
  29.                     } else {  
  30.                         // Got a message.  
  31.                         mBlocked = false;  
  32.                         if (prevMsg != null) {  
  33.                             prevMsg.next = msg.next;  
  34.                         } else {  
  35.                             mMessages = msg.next;  
  36.                         }  
  37.                         msg.next = null;  
  38.                         if (false) Log.v("MessageQueue""Returning message: " + msg);  
  39.                         msg.markInUse();  
  40.                         return msg;  
  41.                     }  
  42.                 } else {  
  43.                     // No more messages.  
  44.                     nextPollTimeoutMillis = -1;  
  45.                 }  
  46.   
  47.                 // Process the quit message now that all pending messages have been handled.  
  48.                 if (mQuitting) {  
  49.                     dispose();  
  50.                     return null;  
  51.                 }  
  52.   
  53.                 // If first time idle, then get the number of idlers to run.  
  54.                 // Idle handles only run if the queue is empty or if the first message  
  55.                 // in the queue (possibly a barrier) is due to be handled in the future.  
  56.                 if (pendingIdleHandlerCount < 0  
  57.                         && (mMessages == null || now < mMessages.when)) {  
  58.                     pendingIdleHandlerCount = mIdleHandlers.size();  
  59.                 }  
  60.                 if (pendingIdleHandlerCount <= 0) {  
  61.                     // No idle handlers to run.  Loop and wait some more.  
  62.                     mBlocked = true;  
  63.                     continue;  
  64.                 }  
  65.   
  66.                 if (mPendingIdleHandlers == null) {  
  67.                     mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];  
  68.                 }  
  69.                 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);  
  70.             }  
  71.   
  72.             // Run the idle handlers.  
  73.             // We only ever reach this code block during the first iteration.  
  74.             for (int i = 0; i < pendingIdleHandlerCount; i++) {  
  75.                 final IdleHandler idler = mPendingIdleHandlers[i];  
  76.                 mPendingIdleHandlers[i] = null// release the reference to the handler  
  77.   
  78.                 boolean keep = false;  
  79.                 try {  
  80.                     keep = idler.queueIdle();  
  81.                 } catch (Throwable t) {  
  82.                     Log.wtf("MessageQueue""IdleHandler threw exception", t);  
  83.                 }  
  84.   
  85.                 if (!keep) {  
  86.                     synchronized (this) {  
  87.                         mIdleHandlers.remove(idler);  
  88.                     }  
  89.                 }  
  90.             }  
  91.   
  92.             // Reset the idle handler count to 0 so we do not run them again.  
  93.             pendingIdleHandlerCount = 0;  
  94.   
  95.             // While calling an idle handler, a new message could have been delivered  
  96.             // so go back and look again for a pending message without waiting.  
  97.             nextPollTimeoutMillis = 0;  
  98.         }  
  99.     }  

首先是个包内函数,所以在同一个包中(android.os)的Looper对象能调用到

nativePollOnce(mPtr, nextPollTimeoutMillis);函数待会展开,功能是调用上一讲的epoll_wait,

nextPollTimeoutMillis超时时间为下一条Message的触发时间,如果没有消息则会一直阻塞到超过超时时间

被唤醒后,我们暂时先忽略barrier类型的Message(这是android4.1后加入的一个特性Choreographer,http://blog.csdn.net/innost/article/details/8272867),

如果头结点msg不为null,就判断现在到了这条msg触发时间没有,

如果没到,则nextPollTimeoutMillis设置为这个条消息需要执行的时间和现在的时间差,给for循环下一次调用nativePollOnce时使用

如果到了甚至超过了,则取出这条msg,退出for循环返回这条msg,给上面上的handler进行dispatch


那么nativePollOnce具体是如何实现的呢?

android_os_MessageQueue.cpp

[cpp]  view plain copy
  1. static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,  
  2.         jint ptr, jint timeoutMillis) {  
  3.     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);  
  4.     nativeMessageQueue->pollOnce(timeoutMillis);  
  5. }  


调用到了nativeMessageQueue->pollOnce

android_os_MessageQueue.cpp

[cpp]  view plain copy
  1. void NativeMessageQueue::pollOnce(int timeoutMillis) {  
  2.     mLooper->pollOnce(timeoutMillis);  
  3. }  


调用到了mLooper->pollOnce

同样,在framework/base/libs/utils/Looper.cpp中

[cpp]  view plain copy
  1. int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {  
  2.     int result = 0;  
  3.     for (;;) {  
  4.         while (mResponseIndex < mResponses.size()) {  
  5.             const Response& response = mResponses.itemAt(mResponseIndex++);  
  6.             if (! response.request.callback) {  
  7. #if DEBUG_POLL_AND_WAKE  
  8.                 LOGD("%p ~ pollOnce - returning signalled identifier %d: "  
  9.                         "fd=%d, events=0x%x, data=%p"this,  
  10.                         response.request.ident, response.request.fd,  
  11.                         response.events, response.request.data);  
  12. #endif  
  13.                 if (outFd != NULL) *outFd = response.request.fd;  
  14.                 if (outEvents != NULL) *outEvents = response.events;  
  15.                 if (outData != NULL) *outData = response.request.data;  
  16.                 return response.request.ident;  
  17.             }  
  18.         }  
  19.   
  20.         if (result != 0) {  
  21. #if DEBUG_POLL_AND_WAKE  
  22.             LOGD("%p ~ pollOnce - returning result %d"this, result);  
  23. #endif  
  24.             if (outFd != NULL) *outFd = 0;  
  25.             if (outEvents != NULL) *outEvents = NULL;  
  26.             if (outData != NULL) *outData = NULL;  
  27.             return result;  
  28.         }  
  29.   
  30.         result = pollInner(timeoutMillis);  
  31.     }  
  32. }  
因为这个流程和mResponses无关,先忽略这部分,

调用到pollInner

framework/base/libs/utils/Looper.cpp

[cpp]  view plain copy
  1. nt Looper::pollInner(int timeoutMillis) {  
  2. #if DEBUG_POLL_AND_WAKE  
  3.     LOGD("%p ~ pollOnce - waiting: timeoutMillis=%d"this, timeoutMillis);  
  4. #endif  
  5.   
  6.     int result = ALOOPER_POLL_WAKE;  
  7.     mResponses.clear();  
  8.     mResponseIndex = 0;  
  9.   
  10. #ifdef LOOPER_STATISTICS  
  11.     nsecs_t pollStartTime = systemTime(SYSTEM_TIME_MONOTONIC);  
  12. #endif  
  13.   
  14. #ifdef LOOPER_USES_EPOLL  
  15.     struct epoll_event eventItems[EPOLL_MAX_EVENTS];  
  16.     int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);  
  17.     bool acquiredLock = false;  
  18. #else  
  19.     // Wait for wakeAndLock() waiters to run then set mPolling to true.  
  20.     mLock.lock();  
  21.     while (mWaiters != 0) {  
  22.         mResume.wait(mLock);  
  23.     }  
  24.     mPolling = true;  
  25.     mLock.unlock();  
  26.   
  27.     size_t requestedCount = mRequestedFds.size();  
  28.     int eventCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);  
  29. #endif  
  30.   
  31.     if (eventCount < 0) {  
  32.         if (errno == EINTR) {  
  33.             goto Done;  
  34.         }  
  35.   
  36.         LOGW("Poll failed with an unexpected error, errno=%d", errno);  
  37.         result = ALOOPER_POLL_ERROR;  
  38.         goto Done;  
  39.     }  
  40.   
  41.     if (eventCount == 0) {  
  42. #if DEBUG_POLL_AND_WAKE  
  43.         LOGD("%p ~ pollOnce - timeout"this);  
  44. #endif  
  45.         result = ALOOPER_POLL_TIMEOUT;  
  46.         goto Done;  
  47.     }  
  48.   
  49. #if DEBUG_POLL_AND_WAKE  
  50.     LOGD("%p ~ pollOnce - handling events from %d fds"this, eventCount);  
  51. #endif  
  52.   
  53. #ifdef LOOPER_USES_EPOLL  
  54.     for (int i = 0; i < eventCount; i++) {  
  55.         int fd = eventItems[i].data.fd;  
  56.         uint32_t epollEvents = eventItems[i].events;  
  57.         if (fd == mWakeReadPipeFd) {  
  58.             if (epollEvents & EPOLLIN) {  
  59.                 awoken();  
  60.             } else {  
  61.                 LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);  
  62.             }  
  63.         } else {  
  64.             if (! acquiredLock) {  
  65.                 mLock.lock();  
  66.                 acquiredLock = true;  
  67.             }  
  68.   
  69.             ssize_t requestIndex = mRequests.indexOfKey(fd);  
  70.             if (requestIndex >= 0) {  
  71.                 int events = 0;  
  72.                 if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;  
  73.                 if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;  
  74.                 if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;  
  75.                 if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;  
  76.                 pushResponse(events, mRequests.valueAt(requestIndex));  
  77.             } else {  
  78.                 LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "  
  79.                         "no longer registered.", epollEvents, fd);  
  80.             }  
  81.         }  
  82.     }  
  83.     if (acquiredLock) {  
  84.         mLock.unlock();  
  85.     }  
  86. Done: ;  
  87. #else  
  88.     for (size_t i = 0; i < requestedCount; i++) {  
  89.         const struct pollfd& requestedFd = mRequestedFds.itemAt(i);  
  90.   
  91.         short pollEvents = requestedFd.revents;  
  92.         if (pollEvents) {  
  93.             if (requestedFd.fd == mWakeReadPipeFd) {  
  94.                 if (pollEvents & POLLIN) {  
  95.                     awoken();  
  96.                 } else {  
  97.                     LOGW("Ignoring unexpected poll events 0x%x on wake read pipe.", pollEvents);  
  98.                 }  
  99.             } else {  
  100.                 int events = 0;  
  101.                 if (pollEvents & POLLIN) events |= ALOOPER_EVENT_INPUT;  
  102.                 if (pollEvents & POLLOUT) events |= ALOOPER_EVENT_OUTPUT;  
  103.                 if (pollEvents & POLLERR) events |= ALOOPER_EVENT_ERROR;  
  104.                 if (pollEvents & POLLHUP) events |= ALOOPER_EVENT_HANGUP;  
  105.                 if (pollEvents & POLLNVAL) events |= ALOOPER_EVENT_INVALID;  
  106.                 pushResponse(events, mRequests.itemAt(i));  
  107.             }  
  108.             if (--eventCount == 0) {  
  109.                 break;  
  110.             }  
  111.         }  
  112.     }  
  113.   
  114. Done:  
  115.     // Set mPolling to false and wake up the wakeAndLock() waiters.  
  116.     mLock.lock();  
  117.     mPolling = false;  
  118.     if (mWaiters != 0) {  
  119.         mAwake.broadcast();  
  120.     }  
  121.     mLock.unlock();  
  122. #endif  
  123.   
  124. #ifdef LOOPER_STATISTICS  
  125.     nsecs_t pollEndTime = systemTime(SYSTEM_TIME_MONOTONIC);  
  126.     mSampledPolls += 1;  
  127.     if (timeoutMillis == 0) {  
  128.         mSampledZeroPollCount += 1;  
  129.         mSampledZeroPollLatencySum += pollEndTime - pollStartTime;  
  130.     } else if (timeoutMillis > 0 && result == ALOOPER_POLL_TIMEOUT) {  
  131.         mSampledTimeoutPollCount += 1;  
  132.         mSampledTimeoutPollLatencySum += pollEndTime - pollStartTime  
  133.                 - milliseconds_to_nanoseconds(timeoutMillis);  
  134.     }  
  135.     if (mSampledPolls == SAMPLED_POLLS_TO_AGGREGATE) {  
  136.         LOGD("%p ~ poll latency statistics: %0.3fms zero timeout, %0.3fms non-zero timeout"this,  
  137.                 0.000001f * float(mSampledZeroPollLatencySum) / mSampledZeroPollCount,  
  138.                 0.000001f * float(mSampledTimeoutPollLatencySum) / mSampledTimeoutPollCount);  
  139.         mSampledPolls = 0;  
  140.         mSampledZeroPollCount = 0;  
  141.         mSampledZeroPollLatencySum = 0;  
  142.         mSampledTimeoutPollCount = 0;  
  143.         mSampledTimeoutPollLatencySum = 0;  
  144.     }  
  145. #endif  
  146.   
  147.     for (size_t i = 0; i < mResponses.size(); i++) {  
  148.         const Response& response = mResponses.itemAt(i);  
  149.         if (response.request.callback) {  
  150. #if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS  
  151.             LOGD("%p ~ pollOnce - invoking callback: fd=%d, events=0x%x, data=%p"this,  
  152.                     response.request.fd, response.events, response.request.data);  
  153. #endif  
  154.             int callbackResult = response.request.callback(  
  155.                     response.request.fd, response.events, response.request.data);  
  156.             if (callbackResult == 0) {  
  157.                 removeFd(response.request.fd);  
  158.             }  
  159.   
  160.             result = ALOOPER_POLL_CALLBACK;  
  161.         }  
  162.     }  
  163.     return result;  
  164. }  

主要看#ifdef  LOOPER_USES_EPOLL部分

int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

等待所有attach到mEpollFd上的事件,如果收到唤醒信号继续执行,否则阻塞等待

之后的#ifdef  LOOPER_USES_EPOLL部分

[cpp]  view plain copy
  1. #ifdef LOOPER_USES_EPOLL  
  2.     for (int i = 0; i < eventCount; i++) {  
  3.         int fd = eventItems[i].data.fd;  
  4.         uint32_t epollEvents = eventItems[i].events;  
  5.         if (fd == mWakeReadPipeFd) {  
  6.             if (epollEvents & EPOLLIN) {  
  7.                 awoken();  
  8.             } else {  
  9.                 LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);  
  10.             }  
  11.         } else {  
  12.             if (! acquiredLock) {  
  13.                 mLock.lock();  
  14.                 acquiredLock = true;  
  15.             }  
  16.   
  17.             ssize_t requestIndex = mRequests.indexOfKey(fd);  
  18.             if (requestIndex >= 0) {  
  19.                 int events = 0;  
  20.                 if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;  
  21.                 if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;  
  22.                 if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;  
  23.                 if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;  
  24.                 pushResponse(events, mRequests.valueAt(requestIndex));  
  25.             } else {  
  26.                 LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "  
  27.                         "no longer registered.", epollEvents, fd);  
  28.             }  
  29.         }  
  30.     }  
  31.     if (acquiredLock) {  
  32.         mLock.unlock();  
  33.     }  
  34. Done: ;  

对所有attach在mEpollFd上的事件进行遍历,如果对象文件描述符有mWakeReadPipeFd,则awoken()

framework/base/libs/utils/Looper.cpp

[cpp]  view plain copy
  1. void Looper::awoken() {  
  2. #if DEBUG_POLL_AND_WAKE  
  3.     LOGD("%p ~ awoken"this);  
  4. #endif  
  5.   
  6. #ifdef LOOPER_STATISTICS  
  7.     if (mPendingWakeCount == 0) {  
  8.         LOGD("%p ~ awoken: spurious!"this);  
  9.     } else {  
  10.         mSampledWakeCycles += 1;  
  11.         mSampledWakeCountSum += mPendingWakeCount;  
  12.         mSampledWakeLatencySum += systemTime(SYSTEM_TIME_MONOTONIC) - mPendingWakeTime;  
  13.         mPendingWakeCount = 0;  
  14.         mPendingWakeTime = -1;  
  15.         if (mSampledWakeCycles == SAMPLED_WAKE_CYCLES_TO_AGGREGATE) {  
  16.             LOGD("%p ~ wake statistics: %0.3fms wake latency, %0.3f wakes per cycle"this,  
  17.                     0.000001f * float(mSampledWakeLatencySum) / mSampledWakeCycles,  
  18.                     float(mSampledWakeCountSum) / mSampledWakeCycles);  
  19.             mSampledWakeCycles = 0;  
  20.             mSampledWakeCountSum = 0;  
  21.             mSampledWakeLatencySum = 0;  
  22.         }  
  23.     }  
  24. #endif  
  25.   
  26.     char buffer[16];  
  27.     ssize_t nRead;  
  28.     do {  
  29.         nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));  
  30.     } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));  
  31. }  

awoken()即上一讲中得awoken()函数,用于把mWakeReadPipeFd上的数据读取干净,因为mWakeWriteReadPipeFd可能写入多次

读取干净后下一次epoll_wait时就会等待mWakeWriteReadPipeFd写入,如果没有读取干净,即通知epoll内核和mWakeReadPipeFd这个事件相关的处理完毕了,

否则epoll_wait就一直会触发对应的事件了(不等待新的写入,一直不阻塞)


3 总结

那么至此,enqueueMessage和定义dequeueMessage都解释清楚,感觉豁然开朗了有木有!!!!

下一讲讲nativeapp的线程消息循环处理过程(主要解读android_native_app_glue.c)

欢迎各位指正!!


4 reference

android sdk sourcecode

android framework sourcecode

这篇关于【从源码看Android】03Android MessageQueue消息循环处理机制(epoll实现)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/481371

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount