这是Android Input系列的第三篇文章,前面两篇的地址如下:
- [ANR] Input ANR是怎么产生的
- [Android输入体系] socket衔接的创立
今天首要讲讲App端在收到事情之后,是怎么消费这些事情的。
首先,咱们看一个事情分发的典型Java堆栈:
能够看到,事情是从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