Android Framework 分析---2訊息機制Native層

來源:互聯網
上載者:User

標籤:brief   locate   nts   bool   進程   介面   UI   frame   called   

在Android的訊息機制中。不僅提供了供Application 開發使用的java的訊息迴圈。事實上java的機制終於還是靠native來實現的。在native不僅提供一套訊息傳遞和處理的機制,還提供了自己定義檔案描寫敘述符的I/O時間的監聽機制。以下我們從詳細代碼中分析一下。

Native層的關鍵類:

Looper.cpp.該類中提供了pollOnce 和wake的休眠和喚醒機制。

同一時候在建構函式中也建立 管道 並增加epoll的機制中。來監聽其狀態變化。

Looper::Looper(bool allowNonCallbacks) :        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),        mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {    int wakeFds[2];    int result = pipe(wakeFds);    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);    mWakeReadPipeFd = wakeFds[0];    mWakeWritePipeFd = wakeFds[1];    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",            errno);    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",            errno);    // Allocate the epoll instance and register the wake pipe.    mEpollFd = epoll_create(EPOLL_SIZE_HINT);    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", 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 = mWakeReadPipeFd;    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",            errno);}
詳細epoll機制,請參看我還有一篇。轉載的epoll機制。一種高效改良的poll機制。

事實上looper在整個訊息迴圈中,主要是實現MessageQueue中休眠和喚醒機制。

 struct epoll_event eventItems[EPOLL_MAX_EVENTS];    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);    // Acquire lock.    mLock.lock();    // Check for poll error.    if (eventCount < 0) {        if (errno == EINTR) {            goto Done;        }        ALOGW("Poll failed with an unexpected error, errno=%d", errno);        result = ALOOPER_POLL_ERROR;        goto Done;    }    // Check for poll timeout.    if (eventCount == 0) {#if DEBUG_POLL_AND_WAKE        ALOGD("%p ~ pollOnce - timeout", this);#endif        result = ALOOPER_POLL_TIMEOUT;        goto Done;    }    // Handle all events.#if DEBUG_POLL_AND_WAKE    ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);#endif    for (int i = 0; i < eventCount; i++) {        int fd = eventItems[i].data.fd;        uint32_t epollEvents = eventItems[i].events;        if (fd == mWakeReadPipeFd) {            if (epollEvents & EPOLLIN) {                awoken();            } else {                ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);            }        } else {            ssize_t requestIndex = mRequests.indexOfKey(fd);            if (requestIndex >= 0) {                int events = 0;                if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;                if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;                if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;                if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;                pushResponse(events, mRequests.valueAt(requestIndex));            } else {                ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "                        "no longer registered.", epollEvents, fd);            }        }    

從以上代碼中能夠看出,looper的pollonce主要在監聽管道的read端是否有事件到來,同一時候在else以下能夠實現對 自己定義檔案描寫敘述符的監聽作用。

詳細擷取下個訊息,還是在MessageQueue.java 的next()實現並返回一個msg。

那什麼時候應該喚醒和怎麼喚醒呢?

參看MessageQueue的代碼。在相關隊列中加入一個msg時。調用用nativeWake方法

static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) {    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);    return nativeMessageQueue->wake();}void Looper::wake() {#if DEBUG_POLL_AND_WAKE    ALOGD("%p ~ wake", this);#endif    ssize_t nWrite;    do {        nWrite = write(mWakeWritePipeFd, "W", 1);    } while (nWrite == -1 && errno == EINTR);    if (nWrite != 1) {        if (errno != EAGAIN) {            ALOGW("Could not write wake signal, errno=%d", errno);        }    }}
喚醒的方法就是向mWakeWirtePipeFd寫一個‘w‘,觸發epoll的mWakeReadPipFdd喚醒進程,進而從MessageQueue的next方法,擷取下一個msg。

final Message next() {        int pendingIdleHandlerCount = -1; // -1 only during first iteration        int nextPollTimeoutMillis = 0;        for (;;) {            if (nextPollTimeoutMillis != 0) {                Binder.flushPendingCommands();            }            nativePollOnce(mPtr, nextPollTimeoutMillis);            synchronized (this) {                if (mQuiting) {                    return null;                }                // Try to retrieve the next message.  Return if found.                final long now = SystemClock.uptimeMillis();                Message prevMsg = null;                Message msg = mMessages;                if (msg != null && msg.target == null) {                    // Stalled by a barrier.  Find the next asynchronous message in the queue.                    do {                        prevMsg = msg;                        msg = msg.next;                    } while (msg != null && !msg.isAsynchronous());                }                if (msg != null) {                    if (now < msg.when) {                        // Next message is not ready.  Set a timeout to wake up when it is ready.                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);                    } else {                        // Got a message.                        mBlocked = false;                        if (prevMsg != null) {                            prevMsg.next = msg.next;                        } else {                            mMessages = msg.next;                        }                        msg.next = null;                        if (false) Log.v("MessageQueue", "Returning message: " + msg);                        msg.markInUse();                        return msg;                    }                } else {                    // No more messages.                    nextPollTimeoutMillis = -1;                }


Looper對檔案描寫敘述符監控和處理:

 looper能夠對普通檔案,裝置檔案或通訊端都能夠監聽。android本身已經提供了一套機制。

/** * Adds a new file descriptor to be polled by the looper. * If the same file descriptor was previously added, it is replaced. * * "fd" is the file descriptor to be added. * "ident" is an identifier for this event, which is returned from ALooper_pollOnce(). * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback. * "events" are the poll events to wake up on.  Typically this is ALOOPER_EVENT_INPUT. * "callback" is the function to call when there is an event on the file descriptor. * "data" is a private data pointer to supply to the callback. * * There are two main uses of this function: * * (1) If "callback" is non-NULL, then this function will be called when there is * data on the file descriptor.  It should execute any events it has pending, * appropriately reading from the file descriptor.  The 'ident' is ignored in this case. * * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce * when its file descriptor has data available, requiring the caller to take * care of processing it. * * Returns 1 if the file descriptor was added or -1 if an error occurred. * * This method can be called on any thread. * This method may block briefly if it needs to wake the poll. */int ALooper_addFd(ALooper* looper, int fd, int ident, int events,        ALooper_callbackFunc callback, void* data);

通過以上介面,大家能夠在native層實現各種檔案的監聽和處理。另外android 還提供Native層的message和MessageHandler來處理訊息機制。

這些都在Looper.h檔案裡。大家有時間能夠研究一下。

/** * 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;};
感覺和java的非常類似吧。







Android Framework 分析---2訊息機制Native層

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.