触摸事件分发流程详解分三个部分分析
建立InputChannel
事件发送和接受
触摸事件分发
这里分析从ViewRootImpl开始:
ViewRootImpl的setView:
触摸事件java端的入口可以从ViewRootImpl的setView讲起,什么时候调用的setView可以查看window的界面显示机制。
对于输入事件分发机制来说,这个setView主要做了四件事:
- 在这里创建了客户端的InputChannel对象。
- 通过binder机制,调用WindowSession的addToDisplay方法,并将InputChannel传入进去。
- 创建WindowInputEventReveiver对象,用来启动inputStage的责任链机制。
- 创建7个InputStage责任链的节点。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
........................
//这个requestLayout是开启的view的绘制流程
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
1、这里直接创建了一个客户端的InputChannel;
mInputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
2、通过Binder调用,进入system进程的Session,同时将客户端的InputChannel作为参数传入。
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch (RemoteException e) {
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
........................
if (view instanceof RootViewSurfaceTaker) {
mInputQueueCallback =
((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
}
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
3、在这里创建了WindowInputEventReveiver对象。
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
view.assignParent(this);
mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
if (mAccessibilityManager.isEnabled()) {
mAccessibilityInteractionConnectionManager.ensureConnection();
}
if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
4、在这里创建了7个InputStage的责任链,按顺序执行,ViewPostImeInputStage这个是关键。
CharSequence counterSuffix = attrs.getTitle();
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
}
}
}
WindowsManagerService的addWindow:
第二步中的会调用mWindowSession.addToDisplay()方法,这是通过binder机制,最终是调用了WindowsManagerService中的addWindow方法。
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
....................
synchronized(mWindowMap) {
...................
1、这里创建一个WindowState 是窗口对象
WindowState win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent)
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
2、然后通过win中的openInputChannel创建socket pair,注意这里跟老版本不同,之前是在这里直接创建的,现在都移到WindowState中去了
win.openInputChannel(outInputChannel);
}
...................
}
return res;
}
WindowState中的openInputChannel:
这里通过openInputChannel方法创建了一对InputChannel,将服务端的InputChannel注册到InputDispatch中,将客户端的InputChannel返回给客户端应用,这样就是实现了客户端和服务端的通信。这里的InputChannel其实就是socket,也就是说输入事件的通信是通过socket实现的,当用户调用InputChannel.sendMessage也就是调用socket.send方法。
void openInputChannel(InputChannel outInputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
String name = makeInputChannelName();
1、创建socket pair用于通信,注意,这里的socket是成对创建的。
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
2、将服务端的socket赋给服务端的WindowState
mInputChannel = inputChannels[0];
3、将客户端的socket赋给客户端的WindowState
mClientChannel = inputChannels[1];
mInputWindowHandle.inputChannel = inputChannels[0];
if (outInputChannel != null) {
4、将客户端的socket放入outInputChannel,最终返回客户端应用进程
mClientChannel.transferTo(outInputChannel);
mClientChannel.dispose();
mClientChannel = null;
} else {
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
}
5、最终将服务端的socket(win.mInputChannel)注册到inputDispatch中。这里的registerInputChannel是一个native方法,调用的就是底层的
mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
}
inputDispatch中的registerInputChannel:
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
#endif
{ // acquire lock
AutoMutex _l(mLock);
if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().string());
return BAD_VALUE;
}
1、这里会创建一个connection对象,并将inputChannel放进去,这个connection就是客户端和服务端的数据通道。每个connection都回对应一个服务端的InputChannel,每个connection都会对应一个socket Pair的fd;
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
int fd = inputChannel->getFd();
2、同时,InputDispatch会将fd最为键,connection作为值,添加到mConnectionsByFd中
mConnectionsByFd.add(fd, connection);
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
3、然后,InputDispatch会将服务端的fd通过Looper的addFd方法,注册到Looper中去,这样,其中一端socket写内容的时候,looper就会知道,并且被唤醒,调用looper.wake()方法,最后在handleReceiveCallback回调函数中获取数据。那么客户端的socket什么时候注册呢?
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
}
mLooper->wake();
return OK;
}
4、在ViewRootImpl的setView中我们最后创建了WindowInputEventReceiver对象,这个对象继承InputEventReceiver,它的构造里,就调用了nativeInit方法,这个native方法是在NativeInputEventReceiver.cpp中实现的。
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
...............
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
mCloseGuard.open("dispose");
}
status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
5、中这里将客户端的fd也注册到了Looper中去,这样就完成,两个socket都是通过Looper来监听的,一旦有动作就会被唤醒。
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}