Android Framework 分析---2消息机制Native层

在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的非常类似吧。

时间: 2024-10-12 12:37:42

Android Framework 分析---2消息机制Native层的相关文章

Android Framework 分析---消息机制Native层

在Android的消息机制中,不仅提供了供Application 开发使用的java的消息循环.其实java的机制最终还是靠native来实现的.在native不仅提供一套消息传递和处理的机制,还提供了自定义文件描述符的I/O时间的监听机制.下面我们从具体代码中分析一下. Native层的关键类: Looper.cpp.该类中提供了pollOnce 和wake的休眠和唤醒机制.同时在构造函数中也创建 管道 并加入epoll的机制中,来监听其状态变化. Looper::Looper(bool al

Android Framework 分析---PackageManager 分析

在windowphone,ios和android中到目前为止,还是android的市场份额最大.个人认为除了google开源外,广大开发者早就了android的霸主地位.各位兄弟姐妹开发出各种各样的apk,才组成android的广阔天下.本篇主要分析一下android系统是针对处理这些apk的,主要涉及到pm这块的代码.分析这种底层服务,最好从android的开启启动流程中开始分析.因为这样才能更清楚的了解服务的启动流程. 1.在SystemServer.java 中启动PM android 开

Chrome浏览器扩展开发系列之十四:本地消息机制Native messagin

Chrome浏览器扩展开发系列之十四:本地消息机制Native messaging 2016-11-24 09:36 114人阅读 评论(0) 收藏 举报  分类: PPAPI(27)  通过将浏览器所在客户端的本地应用注册为Chrome浏览器扩展的"本地消息主机(native messaging host)",Chrome浏览器扩展还可以与客户端本地应用之间收发消息. 客户端的本地应用注册为Chrome浏览器扩展的"本地消息主机"之后,Chrome浏览器会在独立的

【Android自助餐】Handler消息机制完全解析(一)Message中obtain()与recycle()的来龙去脉

[Android自助餐]Handler消息机制完全解析(一)Message中obtain()与recycle()的来龙去脉 Android自助餐Handler消息机制完全解析一Message中obtain与recycle的来龙去脉 提供obtain 回收recycle 提供obtain() 在obtain的所有重载方法中,第一行都是Message m = obtain();,即调用空参的方法. 先来看一下这个空参方法 public static Message obtain() { synchr

android开发系列之消息机制

最近接触到一个比较有挑战性的项目,我发现里面使用大量的消息机制,现在这篇博客我想具体分析一下:android里面的消息到底是什么东西,消息机制到底有什么好处呢? 其实说到android消息机制,我们可能很快就会想到message/handle/looper这三个对象,没错在android里面就是通过此三个对象实现消息机制的.那么我想问的是,为什么我们需要消息机制呢?说到底就是为了更好.更流畅的用户体验,因为在app里面我们或多或少都有可能会设计到一些比较耗时的操作,这个时候如果我们只是一味的将当

【Android自助餐】Handler消息机制完全解析(二)MessageQueue的队列管理

Android自助餐Handler消息机制完全解析(二)MessageQueue的队列管理 Android自助餐Handler消息机制完全解析二MessageQueue的队列管理 添加到消息队列enqueueMessage 从队列取出消息next 第一段 第三段 第二段 从队列移除消息removeMessages 第一个while 第二个while 关于这个队列先说明一点,该队列的实现既非Collection的子类,亦非Map的子类,而是Message本身.因为Message本身就是链表节点(见

Android中的Handler消息机制

转自:http://blog.csdn.net/liuhe688/article/details/6407225 在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListener { private TextView stateText; private Button btn; @Override public void onCreate(Bundle

Android学习笔记之消息机制

Android的消息机制主要是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程.   1.为什么要使用Handler? Android规定访问UI只能在主线程中进行,如果在子线程中访问UI,则会抛出异常.同时Android建议不能在主线程中进行耗时的操作,不然会导致程序无法响应即ANR.因此耗时的工作只能交给子线程去做,而子线程却不能直接访问UI,为了解决这个矛盾,Android提供了Handler.Handler的主要作用是将某个任务切换到某

Android消息传递之Handler消息机制(一)

前言: 无论是现在所做的项目还是以前的项目中,都会遇见线程之间通信.组件之间通信,目前统一采用EventBus来做处理,在总结学习EventBus之前,觉得还是需要学习总结一下最初的实现方式,也算是不忘初心吧,这也是今天来学习总结Handler消息机制的一个原因. Handler机制产生背景 一个Android应用程序被创建的时候都会创建一个UI主线程,但是有时我们会有一些比较耗时的操作,为了防止阻塞UI主线程,我们会将耗时的操作放到子线程中进行处理,处理完之后操作UI,但是Android不允许