本篇接着AndroidQ Handle消息机制(java层)分析native层的相关实现,我们一般了解handler的都知道在有消息的时候取出消息进行处理,没有消息则陷入休眠,但我们从上一篇并没有看到哪里有明显的睡眠和唤醒,其实这都是在native层实现的,可以说handler消息机制的核心就在native层,所以我们这篇文章来看看native的实现细节
MessageQueue中有许多的native方法,我们这篇文章主要分析nativeInit,nativePollOnce和nativeWake
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
@UnsupportedAppUsage
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
private native static void nativeWake(long ptr);
private native static boolean nativeIsPolling(long ptr);
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
在MessageQueue初始化时构造方法中调用了nativeInit,我们首先来看看这个方法:
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
通过JNI到native层
android_os_MessageQueue.cpp
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
//创建NativeMessageQueue
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return 0;
}
//增加强引用
nativeMessageQueue->incStrong(env);
//将nativeMessageQueue返回到java层保存在mPtr中
return reinterpret_cast<jlong>(nativeMessageQueue);
}
NativeMessageQueue构造函数
NativeMessageQueue::NativeMessageQueue() :
mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
//获取当前线程的Looper对象
mLooper = Looper::getForThread();
//如果没有则创建Looper
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
此处的getForThread,setForThread和java ThreadLocal的set,get同样的作用,Looper属于线程私有,注意native层的Looper和java层的Looper是两个东西,并没有关系
Looper.cpp
Looper.cpp在system目录下,不在framework目录下
Looper::Looper(bool allowNonCallbacks)
: mAllowNonCallbacks(allowNonCallbacks),
mSendingMessage(false),
mPolling(false),
mEpollRebuildRequired(false),
mNextRequestSeq(0),
mResponseIndex(0),
mNextMessageUptime(LLONG_MAX) {
//创建一个唤醒事件fd
mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));
AutoMutex _l(mLock);
//重建epoll
rebuildEpollLocked();
}
Looper构造函数中做了两件事,1.调用eventfd创建mWakeEventFd,2.调用rebuildEpollLocked重建epoll
eventfd是Linux提供的一种系统调用,可以用来实现事件通知,通过调用eventfd会返回一个文件描述符,利用IO多路复用机制epoll可以监听该描述符,实现线程间等待/通知
rebuildEpollLocked
void Looper::rebuildEpollLocked() {
//如果有旧的epoll则先关闭掉
if (mEpollFd >= 0) {
mEpollFd.reset();
}
//创建epoll并注册wake管道
mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
//epoll事件为可读事件
eventItem.events = EPOLLIN;
//将创建的唤醒事件的fd设置到eventItem
eventItem.data.fd = mWakeEventFd.get();
//epoll_ctl将mWakeEventFd添加到创建的mEpollFd进行监听
int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
//这里遍历mRequests,将其他的事件,如Input,键盘等也添加到epoll进行
//监听,mRequests中的fd是通过调用Looper.addFd添加的,
//这些事件和Handler消息机制没有关系
for (size_t i = 0; i < mRequests.size(); i++) {
const Request& request = mRequests.valueAt(i);
struct epoll_event eventItem;
request.initEventItem(&eventItem);
//epoll_ctl方法用作添加fd到epoll进行监听
int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
if (epollResult < 0) {
....//error
}
}
}
在rebuildEpollLocked方法中,通过epoll机制,来实现线程间的等待与唤醒操作,Linux系统的epoll机制可以监听大批量的fd,其效率远远强于select/poll,epoll除了监听通过eventfd创建的唤醒文件描述符外,还可以监控其他的文件描述符,native层的Looper提供了addFd接口来添加文件描述符到Looper对象中,当这些被监控的文件描述符上有事情发生时,就会唤醒相应的线程来处理,比如在Input系统中UI线程和InputDispatcher线程的Looper都会调用addFd分别将InputChannel的客户端socket和服务端socket添加到各自的epoll进行监听,以便进行通信从而实现事件分发和处理
epoll机制是包含了epoll_create、epoll_create1、epoll_ctl和epoll_wait这几个方法
epoll_create1:
功能:epoll_create1(EPOLL_CLOEXEC)
创建一个epoll的实例 参数接收一个flag值,如果传入0就等价于epoll_create(0)
EPOLL_CLOEXEC:如果这个参数设置为这个,那么当进程替换映像的时候会关闭这个文件描述符,这样新的映像中就无法对这个文件描述符操作,适用于多进程编程+映像替换的环境里。
返回值:
success:返回一个非0 的未使用过的最小的文件描述符
error:-1
epoll_ctl:
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
对文件描述符进行操作
参数:
epfd:epoll_create1的返回值
op:执行的命令
EPOLL_CTL_ADD:向epoll实例中添加一个的文件描述符来监听
EPOLL_CTL_MOD:改变epoll实例中的一个文件描述符
EPOLL_CTL_DEL:移除epoll实例中的一个文件描述符的监听
fd:要操作的文件描述符
epoll_event:需要监听的事件
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表示已超时
nativeInit函数已经分析完毕,主要做的事情就是创建NativeMessageQueue,在NativeMessageQueue中创建线程私有Looper,在Looper构造函数中创建唤醒事件的fd mWakeEventFd,并创建epoll,将mWakeEventFd添加到epoll进行监听,此fd用来唤醒handler机制中MessageQueue的阻塞状态
接着分析nativePollOnce方法,此方法在MessageQueue.next中调用
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
for (;;) {
...
nativePollOnce(ptr, nextPollTimeoutMillis);
...
}
nativePollOnce
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
NativeMessageQueue->pollOnce
可以看到直接调用了Looper的pollOnce方法,注意这个timeoutMillis,是java层传递下来的,代表下一个msg的执行时间
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;
}
}
mLooper->pollOnce
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
// 先处理没有Callback的Response事件
while (mResponseIndex < mResponses.size()) {
....
}
//待后面pollInner返回不为0的result后退出循环
if (result != 0) {
if (outFd != nullptr) *outFd = 0;
if (outEvents != nullptr) *outEvents = 0;
if (outData != nullptr) *outData = nullptr;
return result;
}
//核心方法
result = pollInner(timeoutMillis);
}
}
Looper::pollInner()
int Looper::pollInner(int timeoutMillis) {
// 调整msg的处理时间,timeoutMillis != 0有两种情况,一是=-1,表明java层
//此时没有msg,二是msg正常延迟执行的时间,mNextMessageUptime代表native
//层的msg的执行时间
if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
if (messageTimeoutMillis >= 0
&& (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
timeoutMillis = messageTimeoutMillis;
}
}
......
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
//调用epoll_wait进入等待状态,返回值是epoll上监听的事件上报的数量
//epoll_wait返回有三种情况:1.有事件上报,2.timeoutMillis时间到了
//3.发生错误
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
......
//发生异常
if (eventCount < 0) {
if (errno == EINTR) {
goto Done;
}
result = POLL_ERROR;
goto Done;
}
// 超时唤醒
if (eventCount == 0) {
result = POLL_TIMEOUT;
goto Done;
}
//当有事件上报则遍历处理所有事件,eventCount为上报的数量
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
//如果是唤醒事件
if (fd == mWakeEventFd.get()) {
if (epollEvents & EPOLLIN) {
//则清空管道数据,这里就是直接调用read(mWakeEventFd...)
//将write(mWakeEventFd...)的数据读取出来,以便下次能够再次
//阻塞
awoken();
} else {
...
}
} else {
//如果是其他事件
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;
//先将时间push进mResponses中,此处并未处理事件
pushResponse(events, mRequests.valueAt(requestIndex));
} else {
...
}
}
}
Done: ;
//开始处理native层的msg,mMessageEnvelopes为msg容器,MessageEnvelope中
//包含了msg的信息
mNextMessageUptime = LLONG_MAX;
while (mMessageEnvelopes.size() != 0) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
//messageEnvelope.uptime和java层的msg的when一样的作用,代表
//msg处理的时间
if (messageEnvelope.uptime <= now) {
{ // obtain handler
sp<MessageHandler> handler = messageEnvelope.handler;
Message message = messageEnvelope.message;
mMessageEnvelopes.removeAt(0);
mSendingMessage = true;
mLock.unlock();
//使用handler处理消息
handler->handleMessage(message);
} // release handler
mLock.lock();
mSendingMessage = false;
result = POLL_CALLBACK;
} else {
//此消息不是立即处理的,则将时间更新到mNextMessageUptime中
mNextMessageUptime = messageEnvelope.uptime;
break;
}
}
mLock.unlock();
//处理前面添加的requests
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;
...
//核心代码,待用requests的callback的handleEvent函数
int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
removeFd(fd, response.request.seq);
}
response.request.callback.clear();
result = POLL_CALLBACK;
}
}
//将处理结果返回回去
return result;
}
pollInner返回值有四个: enum {
//通过wake()唤醒epoll_wait
POLL_WAKE = -1,
//某个fd被触发唤醒epoll_wait
POLL_CALLBACK = -2,
//超时唤醒epoll_wait
POLL_TIMEOUT = -3,
//发生错误唤醒epoll_wait
POLL_ERROR = -4,
};
pollInner函数已经分析完毕,作一个总结:
- 视情况对timeoutMillis进行重置,timeoutMillis这个时间代表着epoll_wait被唤醒的时间,timeoutMillis有java层和native层的mNextMessageUptime共同决定,说明epoll_wait的唤醒由java层和native层共同决定
- 调用epoll_wait进入等待状态,三种情况能够唤醒epoll_wait,(1)epoll监听的fd被触发,(2)超时唤醒,(3)发生错误被唤醒
- 在epoll_wait被fd触发唤醒之后执行相应的操作,(1)如果是mWakeEventFd则清空管道,(2)如果是其他fd,则将其request添加到Response待稍后处理
- 开始处理native的msg和调用request的callback
pollInner函数处理完native层的msg和request后就返回了java层,接着处理java层的msg,这就是handler消息机制msg处理的优先级
最后我们再来看看nativeWake这个函数,nativeWake作用是唤醒MessageQueue,使得Looper能够继续获取消息处理
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}
void NativeMessageQueue::wake() {
mLooper->wake();
}
mLooper->wake()
void Looper::wake() {
uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
LOG_ALWAYS_FATAL("Could not write wake signal to fd %d (returned %zd): %s",
mWakeEventFd.get(), nWrite, strerror(errno));
}
}
}
TEMP_FAILURE_RETRY是一个宏,作用是失败之后重复尝试,这里就是向mWakeEventFd中写入字符,起到通知的作用,前面已经分析过,在nativeInit中创建Looper对象时创建了mWakeEventFd,并在rebuildEpollLocked中将此fd添加到了epoll进行监听,所以当向mWakeEventFd写数据之后就会唤醒epoll_wait,以便能够返回到java层进行消息处理。
到这里我们已经分析完了native层的消息机制,作一个总结:
- java层的Looper创建时会创建MessageQueue,MessageQueue构造方法中调用nativeInit方法到native层,此方法主要作用是创建native层的MessageQueue,并创建native层的Looper,在Looper构造函数中创建了唤醒事件文件描述符mWakeEventFd,并调用rebuildEpollLocked函数创建epoll,epoll创建之后会添加mWakeEventFd以及mRequests中的所有fd进行监听
- java层Looper通过loop方法死循环调用MessageQueue的next方法获取msg,在next方法中会先调用nativePollOnce到native层去处理native的msg,首先会处理没有Callback方法的Response事件,接着调用pollInner函数,此函数里调用epoll_wait陷入等待,唤醒条件有三个:(1)超时唤醒,(2)发生异常唤醒,(3)收到事件上报,无论mWakeEventFd事件还是其他事件,epoll被唤醒后会根据eventCount事件数量遍历处理事件,处理顺序是,首先MessageEnvelope中的msg,其次mResponses中的request的callback,最后返回java层,处理java的msg
- nativeWake用作唤醒epoll,简单的向mWakeEventFd写入一个字符,起到通知的作用
我们可以看出来java层的handler机制非常依赖native层的epoll和管道机制