这是Android Input系列的第三篇文章,前面两篇的地址如下:
今天主要讲讲App端在收到事件之后,是如何消费这些事件的。
首先,我们看一个事件分发的典型Java堆栈:
image.png
可以看到,事件是从nativePollOnce
分发出来的,调到了InputDispatcherReceiver
的onReceive
方法中,然后再分发给ViewRootImpl
去处理。
今天这篇文章,主要讲一下App端从socket中收到事件后,是怎样调度到InputDispatcherReceiver.onReceive
方法的。下一篇文章,我们再讲后续ViewRootImpl
的分发流程。
开始之前,先要要说明的是,接收事件的是App端的主线程,最后分发和处理事件,也是在主线程进行操作。
之前我们讲MessageQueue
的时候说过,主线程会等待在epoll_wait
方法,直到监听的端口有内容写入,才会被唤醒,继续执行下面的流程。更详细的内容,可以去看看我之前的文章从epoll机制看MessageQueue
点击事件的处理流程就是利用的epoll机制,就是我们常说的主线程的Looper
机制,下面我们一起来详细看看源码。
epoll机制监听socketFd
由前面的分析知道,我们在创建了socket连接后,会创建一个WindowInputEventReceiver
对象,并将客户端的InputChannel作为构造函数传入。下面我们就来看看WindowInputEventReceiver
的构造方法。
final class WindowInputEventReceiver extends InputEventReceiver {
//inputChannel是指socket客户端,Looper是指UI线程的Looper
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
}
WindowInputEventReceiver
继承自InputEventReceiver
。
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
...
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue(); //UI线程消息队列
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
}
InputEventReceiver
调用的是nativeInit
方法,进行初始化
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject inputChannelObj, jobject messageQueueObj) {
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
//获取UI主线程的消息队列
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
//创建NativeInputEventReceiver对象
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
// 调用setFdEvents,将socket连接的fd添加到主线程Looper的监控中
status_t status = receiver->initialize();
return reinterpret_cast<jlong>(receiver.get());
}
在nativeInit
方法中,最终会调用setFdEvents
方法,将socket
连接的fd添加到主线程Looper
的监控中。socket连接的fd通过InputChannel获取。
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
//将socket客户端的fd添加到主线程的消息池
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
addFd
方法,就是通过epoll_ctl
将fd加入监听,同时构造一个Request
对象,将它加到mRequests
队列中。
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
{
// 构造request
Request request;
request.fd = fd;
request.ident = ident;
request.events = events;
request.seq = mNextRequestSeq++;
request.callback = callback; //是指nativeInputEventReceiver
request.data = data;
// 构造eventItem
struct epoll_event eventItem;
request.initEventItem(&eventItem);
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
//通过epoll监听fd
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
//该fd的request加入到mRequests队列
mRequests.add(fd, request);
} else {
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
mRequests.replaceValueAt(requestIndex, request);
}
}
return 1;
}
我们来看看Request
的结构:
- fd:存的是socket通信的fd
- ident:0
- events:ALOOPER_EVENT_INPUT
- callback:就是nativeInputEventReceiver
epoll_wait被唤醒
当监听的socket
收到数据时,会从pollInner
方法唤醒主线程Looper
处理消息。
int Looper::pollInner(int timeoutMillis) {
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状态
//循环遍历,处理所有的事件
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
// 如果是从wakeEventFd唤醒,表示MessageQueue有新消息了,会往这个fd写入
if (fd == mWakeEventFd) {
if (epollEvents & EPOLLIN) {
// 这个方法会读取mWakeEventFd上的所有数据
awoken();
}
} else {
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex >= 0) {
//处理request,生成对应的reponse对象,push到mResponses数组
pushResponse(events, mRequests.valueAt(requestIndex));
}
}
}
Done: ;
//处理带有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);
// 正常处理事件会返回1,如果返回0,表示窗口被移除
if (callbackResult == 0) {
removeFd(fd, response.request.seq); //移除fd
}
response.request.callback.clear(); //清除reponse引用的回调方法
result = POLL_CALLBACK; // 发生回调
}
}
return result;
}
这个方法的流程:
- 获取唤醒的fd和events,从
mRequest
中找到对应fd的request
- 将events和request封装成一个
response
对象,然后将他加到mResponses
数组中 - 循环处理
mResponses
数组中的所有response,调用request.callback->handleEvent
这个方法会调到request.callback->handleEvent
,也就是NativeInputEventReceiver
的handleEvent
方法。这个方法主要调用了consumeEvents
,所以我们直接看ConsumeEvents
方法。
读取并消费所有的message
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
// 循环消费所有的消息
for (;;) {
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
if (inputEventObj) {
//执行Java层的InputEventReceiver.dispachInputEvent
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
} else {
skipCallbacks = true;
}
}
if (skipCallbacks) {
//发生异常,则直接向InputDispatcher线程发送完成信号。
mInputConsumer.sendFinishedSignal(seq, false);
}
}
}
循环读取所有的消息,并且调用Java层的InputEventReceiver.dispatchInputEvent
方法处理事件。
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
//循环遍历所有的Event
while (!*outEvent) {
if (mMsgDeferred) {
mMsgDeferred = false; //上一次没有处理的消息
} else {
// 通过InputChannel接收一条消息
status_t result = mChannel->receiveMessage(&mMsg);
if (result) {
if (consumeBatches || result != WOULD_BLOCK) {
result = consumeBatch(factory, frameTime, outSeq, outEvent);
}
}
}
}
}
return OK;
}
单条消息,调用InputChannel
的receiveMessage
读取。
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
//读取InputDispatcher发送过来的消息
nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
return OK;
}
Java端收到事件后,会回调到WindowInputEventReceiver
的onInputEvent
方法中,处理事件。
发送处理完信号
当事件处理完后,会调用finishInputEvent
方法,将处理完的结果返回给系统。
从Java端的InputEventReceiver
开始。
public final void finishInputEvent(InputEvent event, boolean handled) {
int seq = mSeqMap.valueAt(index);
mSeqMap.removeAt(index);
// 调用native的方法
nativeFinishInputEvent(mReceiverPtr, seq, handled);
}
调用到NativeInputEventReceiver
,最终调用到sendFinishedSignal
,然后调用到sendUnchainedFinishedSignal
。
status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
// 组装一个finished的信号,通过InputChannel的socket发送给系统
InputMessage msg;
msg.header.type = InputMessage::TYPE_FINISHED;
msg.body.finished.seq = seq;
msg.body.finished.handled = handled;
return mChannel->sendMessage(&msg);
}
总结
App端消费事件的流程如下:
- 在创建完
socketpair
后,App端会用mInputChanne
l创建一个WindowInputEventReceiver
对象,并且注册对socket fd
的监听。 - 当
socket fd
上有输入写入时(即有事件时),会唤醒主线程 - 主线程循环读取socket fd上的
InputMessage
,然后将message
发送给Java层的InputEventReceiver
去处理 - 处理完之后,组装一个
finished
的信号,通过mInputChannel
发送给system_server
网友评论