接着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优势
监视的描述符数量不受限制,所支持的FD上限是最大可以打开文件的数目,具体数目可以
cat /proc/sys/fs/file-max
查看,一般来说这个数目和系统内存关系很大,以3G的手机来说这个值为20-30万。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_framework的3,提取消息中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回调,理解了该流程,也就明白有时上层消息很少,但响应时间却较长的真正原因。
参考文章: