Android的Handler机制详解2_native

15 篇文章 0 订阅
3 篇文章 0 订阅

接着Android的Handler机制详解1_framework 讲。

其实native层也有一套自己的完整的消息处理机制。

1、组成


1.1 MessageHandler

/**
 * 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;
};

1.2 WeakMessageHandler

/**
 * 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;
};

1.3 MessageQueue

class MessageQueue : public virtual RefBase {
public:
    /* Gets the message queue's looper. */
    inline sp<Looper> getLooper() const {
        return mLooper;
    }

    /* Checks whether the JNI environment has a pending exception.
     *
     * If an exception occurred, logs it together with the specified message,
     * and calls raiseException() to ensure the exception will be raised when
     * the callback returns, clears the pending exception from the environment,
     * then returns true.
     *
     * If no exception occurred, returns false.
     */
    bool raiseAndClearException(JNIEnv* env, const char* msg);

    /* Raises an exception from within a callback function.
     * The exception will be rethrown when control returns to the message queue which
     * will typically cause the application to crash.
     *
     * This message can only be called from within a callback function.  If it is called
     * at any other time, the process will simply be killed.
     *
     * Does nothing if exception is NULL.
     *
     * (This method does not take ownership of the exception object reference.
     * The caller is responsible for releasing its reference when it is done.)
     */
    virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) = 0;

protected:
    MessageQueue();
    virtual ~MessageQueue();

protected:
    sp<Looper> mLooper;
};

1.4  NativeMessageQueue

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);

private:
    JNIEnv* mPollEnv;
    jobject mPollObj;
    jthrowable mExceptionObj;
};

1.5 Message

/**
 * A message that can be posted to a Looper.
 */
struct Message {
    Message() : what(0) { }
    Message(int what) : what(what) { }

    /* The message type. (interpretation is left up to the handler) */
    int what;
};

2、发送消息

2.1 Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message);

void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    sendMessageAtTime(now, handler, message);
}
2.2 Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,

            const Message& message);

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);
}
2.3 Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,

            const Message& message);

void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
        const Message& message) {
    size_t i = 0;
    { //请求锁
        AutoMutex _l(mLock);
        size_t messageCount = mMessageEnvelopes.size();
        //找到message应该插入的位置i
        while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
            i += 1;
        }
        MessageEnvelope messageEnvelope(uptime, handler, message);
        mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
        //如果当前正在发送消息,那么不再调用wake(),直接返回。
        if (mSendingMessage) {
            return;
        }
    } //释放锁
    //当把消息加入到消息队列的头部时,需要唤醒poll循环。
    if (i == 0) {
        wake();
    }
}

可以看到发送消息最终都是条用的sendMessageAtTime这个函数,最终把消息按照时间的顺序插入到了mMessageEnvelopes中了。

2.4 MessageEnvelope

   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;
    };

3、提取消息

3.1 Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    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 (outFd != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }
        if (result != 0) {
            if (outFd != NULL) *outFd = 0;
            if (outEvents != NULL) *outEvents = 0;
            if (outData != NULL) *outData = NULL;
            return result;
        }
        // 再处理内部轮询
        result = pollInner(timeoutMillis);
    }
}

参数说明:

    timeoutMillis:超时时长

    outFd:发生事件的文件描述符

    outEvents:当前outFd上发生的事件,包含以下4类事件    

  • EVENT_INPUT 可读
  • EVENT_OUTPUT 可写
  • EVENT_ERROR 错误
  • EVENT_HANGUP 中断

    outData:上下文数据

3.2 Looper::pollInner(int timeoutMillis)

int Looper::pollInner(int timeoutMillis) {
    ...
    int result = POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;
    mPolling = true; //即将处于idle状态
    struct epoll_event eventItems[EPOLL_MAX_EVENTS]; //fd最大个数为16
    //等待事件发生或者超时,在nativeWake()方法,向管道写端写入字符,则该方法会返回;
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    mPolling = false; //不再处于idle状态
    mLock.lock();  //请求锁
    if (mEpollRebuildRequired) {
        mEpollRebuildRequired = false;
        rebuildEpollLocked();  // epoll重建,直接跳转Done;
        goto Done;
    }
    if (eventCount < 0) {
        if (errno == EINTR) {
            goto Done;
        }
        result = POLL_ERROR; // epoll事件个数小于0,发生错误,直接跳转Done;
        goto Done;
    }
    if (eventCount == 0) {  //epoll事件个数等于0,发生超时,直接跳转Done;
        result = POLL_TIMEOUT;
        goto Done;
    }

    //循环遍历,处理所有的事件
    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeEventFd) {
            if (epollEvents & EPOLLIN) {
                awoken(); //从管道中感知到EPOLLIN,于是调用awoken()
            }
        } else {
            // 如果是除管道以外的其他fd发生了变动,那么根据其对应的request,
            // 将response先记录进mResponses
            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,生成对应的reponse对象,push到响应数组
                pushResponse(events, mRequests.valueAt(requestIndex));
            }
        }
    }
Done: ;
    //再处理Native的Message,调用相应回调方法
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        if (messageEnvelope.uptime <= now) {
            {
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();  //释放锁
                handler->handleMessage(message);  // 处理消息事件
            }
            mLock.lock();  //请求锁
            mSendingMessage = false;
            result = POLL_CALLBACK; // 发生回调
        } else {
            mNextMessageUptime = messageEnvelope.uptime;
            break;
        }
    }
    mLock.unlock(); //释放锁

    //处理带有Callback()方法的Response事件,执行Reponse相应的回调方法
    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;
            // 处理请求的回调方法
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq); //移除fd
            }
            response.request.callback.clear(); //清除reponse引用的回调方法
            result = POLL_CALLBACK;  // 发生回调
        }
    }
    return result;
}

返回值说明:

POLL_WAKE: 表示由wake()触发,即pipe写端的write事件触发;

POLL_CALLBACK: 表示某个被监听fd被触发;

POLL_TIMEOUT: 表示等待超时;

POLL_ERROR:表示等待期间发生错误;

回头看一下Looper::pollOnce()和Looper::pollInner(),在Looper::pollOnce()先处理Response数组中不带Callback的事件,再调用了Looper::pollInner()方法。

重点看一下Looper::pollInner()的执行过程

3.2.1、第9行int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);  这里会发生阻塞等待。只有当被等待的事件发生或者等待超时才会返回。

3.2.2、对于epoll_wait()的返回当且仅当一下情况发生:

POLL_ERROR,发生错误,直接跳转到Done;

POLL_TIMEOUT,发生超时,直接跳转到Done;

测到管道有事件发生,则再根据情况做相应处理:

  • 如果是管道事件mWakeEventFd == mWakeEventFd且epollEvents & EPOLLIN,则调用一下awoken()
  • 如果是其他事件的fd在mRequests键值向量表(KeyedVector<int, Request> mRequests),就将该fd对应的Request整理进Response对象,并将该Response对象记入mResponses表。

3.2.3、Done:

a、先处理Native的Message(mMessageEnvelopes),调用Native 的Handler来处理该Message;

b、再处理Response数组,POLL_CALLBACK类型的事件;

3.3 Request

struct Request {
        int fd;
        int ident;
        int events;
        int seq;
        sp<LooperCallback> callback;
        void* data;

        void initEventItem(struct epoll_event* eventItem) const;
    };

3.4 Response

 struct Response {
        int events;
        Request request;
    };

3.5 LooperCallback

/**
 * 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.
     */
    virtual int handleEvent(int fd, int events, void* data) = 0;
};

3.6 SimpleLooperCallback

/**
 * Wraps a Looper_callbackFunc function pointer.
 */
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;
};

4、处理消息

首先处理mResponse里面的非CALLBACK消息,然后在epoll_wait那里阻塞掉,如果epoll_wait是因为错误或者超时返回的就直接跳转到Done处理事件,否则判断返回的事件的文件描述符是否是mWakeEventFd事件,类型是否是EPOLLIN,如果是就调用awoken()方法。反之判断fd是否在mRequests键值向量表可以查到,如果可以查到那么就将该fd对应的Request整理进Response对象,并将该Response对象记入mResponses表。在Done处理事件最后会用一个for循环遍历mResponses表,分析每个Response表项对应的Request是不是需要callback,如果需要的话,执行对应的回调函数:

int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
    removeFd(fd);
}

可以看到,handleEvent()的返回值将决定那个Request表项是否继续保留在mRequests表中,如果返回值为0,说明不必保留了,所以删除之。删除时会同时从epoll中注销这个Request对应的fd,表示不再对这个fd感兴趣了。

还会集中处理所记录的所有C++层的Message。在一个while循环中,不断摘取mMessageEnvelopes向量表的第0个MessageEnvelope,如果消息已经到时,则回调handleMessage()。

Message message = messageEnvelope.message;
mMessageEnvelopes.removeAt(0);
mSendingMessage = true;
handler->handleMessage(message);  // 处理消息事件

而如果消息未到时,说明while循环可以break了。

5、epoll

select/poll/epoll都是IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作。本质上select/poll/epoll都是同步I/O,即读写是阻塞的。

5.1 select

int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

从select函数监控3类文件描述符:writefds、readfds、exceptfds。调用select函数后会阻塞,直到描述符准备就绪(有数据可读、可写、或者出现异常)或者超时,函数便返回。当select函数返回后,可以通过遍历描述符集合,找到就绪的描述符。

select缺点
  • 单进程能够监控的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义增大上限,但同样存在效率低的弱势;
  • IO效随着监视的描述符数量的增长,其效率也会线性下降;

5.2 poll

int poll (struct pollfd *fds, unsigned int nfds, int timeout);

其中pollfd表示监视的描述符集合,如下:

struct pollfd {
    int fd; //文件描述符
    short events; //监视的请求事件
    short revents; //已发生的事件
};
pollfd结构包含了要监视的event和发生的event,并且pollfd并没有最大数量限制(但数量过大同样会导致性下降)。 和select函数一样,当poll函数返回后,可以通过遍历描述符集合,找到就绪的描述符。

从上面看,select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的socket。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。

5.3 epoll

epoll是在2.6内核中提出的,是select和poll的增强版。相对于select和poll来说,epoll更加灵活,没有描述符数量限制。epoll使用一个文件描述符管理多个描述符,将用户空间的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。epoll机制是Linux最高效的I/O复用机制,在一处等待多个文件句柄的I/O事件。

select/poll都只有一个方法,而epoll的操作过程有3个方法,分别是epoll_create(), epoll_ctl(),epoll_wait()。

5.3.1 epoll_create()

int epoll_create(int size);
用于创建一个epoll的句柄,size是指监听的描述符个数, 现在内核支持动态扩展,该值的意义仅仅是初次分配的fd个数,后面空间不够时会动态扩容。 当创建完epoll句柄后,占用一个fd值.

使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

5.3.2 epoll_ctl()

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
用于对需要监听的文件描述符(fd)执行op操作,比如将fd加入到epoll句柄。
  • epfd:是epoll_create()的返回值;
  • op:表示op操作,用三个宏来表示,分别代表添加、删除和修改对fd的监听事件;
    • EPOLL_CTL_ADD(添加)
    • EPOLL_CTL_DEL(删除)
    • EPOLL_CTL_MOD(修改)
  • fd:需要监听的文件描述符;
  • epoll_event:需要监听的事件,struct epoll_event结构如下:

      struct epoll_event {
        __uint32_t events;  /* Epoll事件 */
        epoll_data_t data;  /*用户可用数据*/
      };

    events可取值:(表示对应的文件描述符的操作)

  • EPOLLIN :可读(包括对端SOCKET正常关闭);

  • EPOLLOUT:可写;

  • EPOLLERR:错误;

  • EPOLLHUP:中断;

  • EPOLLPRI:高优先级的可读(这里应该表示有带外数据到来);

  • EPOLLET: 将EPOLL设为边缘触发模式,这是相对于水平触发来说的。

  • EPOLLONESHOT:只监听一次事件,当监听完这次事件之后就不再监听该事件

5.3.3 epoll_wait()

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

  • epfd:等待epfd上的io事件,最多返回maxevents个事件;
  • events:用来从内核得到事件的集合;
  • maxevents:events数量,该maxevents值不能大于创建epoll_create()时的size;
  • timeout:超时时间(毫秒,0会立即返回)。

该函数返回需要处理的事件数目,如返回0表示已超时。

5.3.4epoll优势

  1. 监视的描述符数量不受限制,所支持的FD上限是最大可以打开文件的数目,具体数目可以cat /proc/sys/fs/file-max查看,一般来说这个数目和系统内存关系很大,以3G的手机来说这个值为20-30万。

  2. IO效率不会随着监视fd的数量增长而下降。epoll不同于select和poll轮询的方式,而是通过每个fd定义的回调函数来实现的,只有就绪的fd才会执行回调函数。

如果没有大量的idle-connection或者dead-connection,epoll的效率并不会比select/poll高很多,但是当遇到大量的idle-connection,就会发现epoll的效率大大高于select/poll。

在 select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait() 时便得到通知。(此处去掉了遍历文件描述符,而是通过监听回调的的机制。这正是epoll的魅力所在。)

6、FrameWork层Handler与Native层handler联系


图解:

  • 红色虚线关系:Java层和Native层的MessageQueue通过JNI建立关联,彼此之间能相互调用,搞明白这个互调关系,也就搞明白了Java如何调用C++代码,C++代码又是如何调用Java代码。
  • 蓝色虚线关系:Handler/Looper/Message这三大类Java层与Native层并没有任何的真正关联,只是分别在Java层和Native层的handler消息模型中具有相似的功能。都是彼此独立的,各自实现相应的逻辑。
  • WeakMessageHandler继承于MessageHandler类,NativeMessageQueue继承于MessageQueue类

MessageQueue是在Java层与Native层有着紧密的联系,但是此次Native层的Looper与Java层的Looper没有任何的关系,可以发现native基本等价于用C++重写了Java的Looper逻辑,故可以发现很多功能类似的地方。

6.1初始化


6.1.1 MessageQueue.java

MessageQueue(boolean quitAllowed) {
    mQuitAllowed = quitAllowed;
    mPtr = nativeInit();  //mPtr记录native消息队列的信息
}

6.1.2  android_os_MessageQueue.cpp

static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); //初始化native消息队列 【3】
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }
    nativeMessageQueue->incStrong(env);
    return reinterpret_cast<jlong>(nativeMessageQueue);
}

6.1.3  android_os_MessageQueue.cpp

NativeMessageQueue::NativeMessageQueue() : mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
    mLooper = Looper::getForThread(); //获取TLS中的Looper对象
    if (mLooper == NULL) {
        mLooper = new Looper(false); //创建native层的Looper
        Looper::setForThread(mLooper); //保存native层的Looper到TLS中
    }
}
  • Looper::getForThread(),功能类比于Java层的Looper.myLooper();
  • Looper::setForThread(mLooper),功能类比于Java层的ThreadLocal.set();

6.1.4 Looper.cpp

Looper::Looper(bool allowNonCallbacks) :
        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
    mWakeEventFd = eventfd(0, EFD_NONBLOCK); //构造唤醒事件的fd
    AutoMutex _l(mLock);
    rebuildEpollLocked();  //重建Epoll事件
}

注意:这里构造了唤醒的mWakeEventFd

6.1.5  Looper.cpp

void Looper::rebuildEpollLocked() {
    if (mEpollFd >= 0) {
        close(mEpollFd); //关闭旧的epoll实例
    }
    mEpollFd = epoll_create(EPOLL_SIZE_HINT); //创建新的epoll实例,并注册wake管道
    struct epoll_event eventItem;
    memset(& eventItem, 0, sizeof(epoll_event)); //把未使用的数据区域进行置0操作
    eventItem.events = EPOLLIN; //可读事件
    eventItem.data.fd = mWakeEventFd;
    //将唤醒事件(mWakeEventFd)添加到epoll实例(mEpollFd)
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);

    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);
        }
    }
}

注意:这里添加mRequest队列。

6.2 清理回收


6.2.1 MessageQueue.java

 private void dispose() {
        if (mPtr != 0) {
            nativeDestroy(mPtr);
            mPtr = 0;
        }
    }

6.2.2 android_os_MessageQueue.cpp

static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->decStrong(env); 
}

nativeMessageQueue继承自RefBase类,所以decStrong最终调用的是RefBase.decStrong().

6.2.3  RefBase.cpp

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id); //移除强引用
    const int32_t c = android_atomic_dec(&refs->mStrong);
    if (c == 1) {
        refs->mBase->onLastStrongRef(id);
        if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            delete this;
        }
    }
    refs->decWeak(id); // 移除弱引用
}

6.3 提取消息


6.3.1 MessageQueue.java

Message next() 
{
    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    
    for (;;) {
        . . . . . .
        nativePollOnce(mPtr, nextPollTimeoutMillis);    // 阻塞于此
        . . . . . .
            // 获取next消息,如能得到就返回之。
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;  // 先尝试拿消息队列里当前第一个消息
            
            if (msg != null && msg.target == null) {
                // 如果从队列里拿到的msg是个“同步分割栏”,那么就寻找其后第一个“异步消息”
                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;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }
            if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }
        . . . . . .
        // 处理idle handlers部分
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf("MessageQueue", "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
        
        pendingIdleHandlerCount = 0;
        nextPollTimeoutMillis = 0;
    }
}

Android的Handler机制详解1_framework3,提取消息中Looper.looper()过程中我们有4个希望:

1)如果消息队列里目前没有合适的消息可以摘取,那么不能让它所属的线程“傻转”,而应该使之阻塞;
2)队列里的消息应该按其“到时”的顺序进行排列,最先到时的消息会放在队头,也就是mMessages域所指向的消息,其后的消息依次排开;
3)阻塞的时间最好能精确一点儿,所以如果暂时没有合适的消息节点可摘时,要考虑链表首个消息节点将在什么时候到时,所以这个消息节点距离当前时刻的时间差,就是我们要阻塞的时长。

4)有时候外界希望队列能在即将进入阻塞状态之前做一些动作,这些动作可以称为idle动作,我们需要兼顾处理这些idle动作。一个典型的例子是外界希望队列在进入阻塞之前做一次垃圾收集。

现在解答一下:

1)next()中调用的nativePollOnce()起到了阻塞作用,保证消息循环不会在无消息处理时一直在那里“傻转”。nativePollOnce→android_os_MessageQueue_nativePollOnce→ NativeMessageQueue::pollOnce→ mLooper->pollOnce(timeoutMillis)→pollInner(timeoutMillis)。经过调用链我们发现最终其实是利用epoll机制来完成阻塞动作的。每当我们向消息队列发送事件时,最终会间接向管道的“写入端”写入数据,这个前文已有叙述,于是epoll通过管道的“读取端”立即就感知到了风吹草动,epoll_wait()在等到事件后,随即进行相应的事件处理。这就是消息循环阻塞并处理的大体流程。当然,因为向管道写数据只是为了通知风吹草动,所以写入的数据是非常简单的“1”字符串。具体过程看6.4唤醒过程就可以知道了。

2)这个在MessageQueue.enqueueMessage(Message msg, long when)就保证了。

3)next()函数里的for循环并不是起循环摘取消息节点的作用,而是为了连贯“当前时间点”和“处理下一条消息的时间点”。简单地说,当“定时机制”触发“摘取一条消息”的动作时,会判断事件队列的首条消息是否真的到时了,如果已经到时了,就直接返回这个msg,而如果尚未到时,则会努力计算(Math.min(msg.when - now, Integer.MAX_VALUE))一个较精确的等待时间(nextPollTimeoutMillis),计算完后,那个for循环会掉过头再次调用到nativePollOnce(mPtr, nextPollTimeoutMillis),进入阻塞状态,从而等待合适的时长。如果消息队列已经是空队列了,那么nextPollTimeoutMillis赋值为-1,只要队列中有Idle Handler需要处理,那么在处理完所有Idle Handler之后,会强制将nextPollTimeoutMillis赋值为0。这主要是考虑到在处理Idle Handler时,不知道会耗时多少,而在此期间消息队列的“到时情况”有可能已发生改变。

4)next()函数当消息队列中没有消息需要马上处理时,会判断用户是否设置了Idle Handler,如果有的话,则会尝试处理mIdleHandlers中所记录的所有Idle Handler,此时会逐个调用这些Idle Handler的queueIdle()成员函数。

6.3.2 MessageQueue.java

 private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/

6.3.3 android_os_MessageQueue.cpp

static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis) {
    //将Java层传递下来的mPtr转换为nativeMessageQueue
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis); 
}
6.3.4 android_os_MessageQueue.cpp
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    mLooper->pollOnce(timeoutMillis); 
    mPollObj = NULL;
    mPollEnv = NULL;
    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}

6.3.5 Looper.h

inline int pollOnce(int timeoutMillis) {
    return pollOnce(timeoutMillis, NULL, NULL, NULL); 
}

6.3.6  Looper.cpp

Looper::pollOnce见:3.1

Looper::pollInner见:3.2

6.3.7 Looper::awoken()

void Looper::awoken() {
    uint64_t counter;
    //不断读取管道数据,目的就是为了清空管道内容
    TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
}

6.4 唤醒过程

nativeWake用于唤醒功能,在添加消息到消息队列enqueueMessage(), 或者把消息从消息队列中全部移除quit(),再有需要时都会调用 nativeWake方法。


6.4.1 MessageQueue.java

boolean enqueueMessage(Message msg, long when) {
    ... //将Message按时间顺序插入MessageQueue
    if (needWake) {
            nativeWake(mPtr); 
        }
}

6.4.2 android_os_MessageQueue.cpp

static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->wake(); 
}

6.4.3 android_os_MessageQueue.cpp

void NativeMessageQueue::wake() {
    mLooper->wake();  
}

6.4.4  Looper.cpp

void Looper::wake() {
    uint64_t inc = 1;
    // 向管道mWakeEventFd写入字符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);
        }
    }
}

其中TEMP_FAILURE_RETRY 是一个宏定义, 当执行write失败后,会不断重复执行,直到执行成功为止。

6.5 Android系统Handler消息处理过程

public static void loop() {  
   ...
    for (;;) { //进入loop的主循环方法  
        Message msg = queue.next(); //可能会阻塞   
      ...  
        msg.target.dispatchMessage(msg); //用于分发Message 
     }  
}  
Message next() 
{
  ... 
    for (;;) {
        . . . . . .
        nativePollOnce(mPtr, nextPollTimeoutMillis);    // 阻塞于此
        . . . . . .
        // 处理idle handlers部分
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf("MessageQueue", "IdleHandler threw exception", t);
            }
        ...
    }
}
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    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 (outFd != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }
        if (result != 0) {
            if (outFd != NULL) *outFd = 0;
            if (outEvents != NULL) *outEvents = 0;
            if (outData != NULL) *outData = NULL;
            return result;
        }
        // 再处理内部轮询
        result = pollInner(timeoutMillis); 
    }
}
int Looper::pollInner(int timeoutMillis) {
    ...
Done: ;
    //再处理Native的Message,调用相应回调方法
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        if (messageEnvelope.uptime <= now) {
            {
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();  //释放锁
                handler->handleMessage(message);  // 处理消息事件
            }
            mLock.lock();  //请求锁
            mSendingMessage = false;
            result = POLL_CALLBACK; // 发生回调
        } else {
            mNextMessageUptime = messageEnvelope.uptime;
            break;
        }
    }
    mLock.unlock(); //释放锁

    //处理带有Callback()方法的Response事件,执行Reponse相应的回调方法
    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;
            // 处理请求的回调方法
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq); //移除fd
            }
            response.request.callback.clear(); //清除reponse引用的回调方法
            result = POLL_CALLBACK;  // 发生回调
        }
    }
    return result;
}

根据上面列举出来的处理消息的相关函数,我们可以知道消息处理流程是先处理Native Message,再处理Native Request,最后处理Java Message,当没有消息是处理idle回调,理解了该流程,也就明白有时上层消息很少,但响应时间却较长的真正原因。

参考文章:

Android消息机制2-Handler(Native层)

聊一聊Android的消息机制

select/poll/epoll对比分析

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值