public final class ViewRootImpl {
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
requestLayout();
// …
// 创建InputChannel
mInputChannel = new InputChannel();
// 通过Binder在SystemServer进程中完成InputChannel的注册
mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
}
这里涉及到了WindowManagerService
和Binder
跨进程通信,读者不需要纠结于详细的细节
只需了解最终在SystemServer
进程中,WindowManagerService
根据当前的Window
创建了SocketPair
用于跨进程通信,同时并对App
进程中传过来的InputChannel
进行了注册
这之后,ViewRootImpl
里的InputChannel
就指向了正确的InputChannel
, 作为Client
端,其fd
与SystemServer
进程中Server
端的fd
组成SocketPair
, 它们就可以双向通信了。
然后我们App
进程的主线程就会监听socket
客户端,当收到消息(输入事件)后,回调NativeInputEventReceiver.handleEvent()
方法,最终会走到InputEventReceiver.dispachInputEvent
方法。
经过以上操作App
终于拿到输入事件了,接下来就是传递到对应页面
1.4小结
关于内核处理输入事件与跨进程通信的部分一般来说不是应用开发者最关注的部分,也不是本文的重点,所以只做了概述
想要了解细节的同学可参考:Input系统—事件处理全过程
现在我们已经在App
进程中拿到输入事件了,接下来看看事件如何分发到页面
我们接下来跟一下源码
2.1 事件回传到ViewRootImpl
//InputEventReceiver.java
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
//ViewRootImpl.java ::WindowInputEventReceiver
final class WindowInputEventReceiver extends InputEventReceiver {
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
}
//ViewRootImpl.java
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
adjustInputEventForCompatibility(event);
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
QueuedInputEvent last = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}
可以看到事件还是回到了ViewRootImpl
中,可见ViewRootImpl
不仅负责界面的绘制,同时负责事件的传递
2.2 第一次责任链分发
接下来走到doProcessInputEvents
中,其中涉及到事件分发中的第一次责任链分发
void doProcessInputEvents() {
…
// Deliver all pending input events in the queue.
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
deliverInputEvent(q);
}
…
}
private void deliverInputEvent(QueuedInputEvent q) {
InputSta