五,接下来的问题是InputDispatch是怎么把事件通知到到焦点窗口InputTarget的呢?
先看下InputTarget的定义,
InputDispatcher.h
一个inputtarget表明了怎样把一个输入事件分发给一个特定的窗口。
struct InputTarget {
enum{
//这个flag指示 事件应该发给前台应用程序。
FLAG_FOREGROUND= 1 << 0,
//这个flag表明,这个motionevent,通常是触摸事件,落在了一个被上面的可见窗口遮盖的区域中了,
FLAG_WINDOW_IS_OBSCURED= 1 << 1,
};
//重点是这个inputChannel,一个inputchannel包含了一个本地的unix domain socket,它用于进程之间发送和接收输入消息,
sp<InputChannel>inputChannel;
}
由此可以知道,InputDispatch跟应用程序通信就是通过这个inputChannel了,既然这样, 每添加一个应用窗口,都要创建一个这样的inputChannel的通道,所以从应用窗口的添加看起:
在一个应用程序第一次启动的时候,肯定要先执行一次View树的遍历,然后再向WindowManagerService申请窗口注册,为什么不是先申请注册窗口,在执行viewtree的遍历呢?以为窗口一旦注册好就意味着可以接收事件、分发事件了,所以在这之前Viewtree要做好接收事件的准备。
ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParamsattrs, View panelParentView){
//这里执行Viewtree的遍历,
requestLayout();
//这里开始申请注册窗口。
mInputChannel= new InputChannel();
res= mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(),mDisplay.getDisplayId(),
mAttachInfo.mContentInsets,mAttachInfo.mStableInsets,
mAttachInfo.mOutsets,mInputChannel);
}
通过Session把请求发到WindowManagerService,只关注InputChannel的创建。
WindowManagerService.java
public int addWindow(Session session,IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel){
win.openInputChannel(outInputChannel);
}
WindowState.java
void openInputChannel(InputChanneloutInputChannel) {
//经过jni调用,就到了通道的本地实现,下面有这个通道详细的本地实现。
String name = makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
mInputChannel= inputChannels[0];
mClientChannel= inputChannels[1];
mInputWindowHandle.inputChannel= inputChannels[0];
//将 mClientChannel客户端的所有权转给了outInputChannel,这个 outInputChannel就是应用程序申请窗口时创建的。
mClientChannel.transferTo(outInputChannel);
//注册一个输入通道input channel并将其关联到输入窗口mInputWindowHandle,把它作为输入事件的target, mInputChannel和 mInputWindowHandle都是被inputdispatcher使用的,下面会分析这个注册的详细代码。
mService.mInputManager.registerInputChannel(mInputChannel,mInputWindowHandle);
}
下面是通道的本地实现,通过socketpare的方式,创建了sockets,一个通道有一个服务端,一个客户端,在这个场景中,服务端提供给InputDispatch-发出事件,客户端提供给应用的输入队列-消费事件,
InputTransport.cpp
status_tInputChannel::openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel,sp<InputChannel>& outClientChannel) {
int sockets[2];
socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)
int bufferSize = SOCKET_BUFFER_SIZE;
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize,sizeof(bufferSize));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize,sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize,sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize,sizeof(bufferSize));
String8 serverChannelName = name;
serverChannelName.append(" (server)");
outServerChannel = new InputChannel(serverChannelName, sockets[0]);
String8 clientChannelName = name;
clientChannelName.append(" (client)");
outClientChannel = new InputChannel(clientChannelName, sockets[1]);
return OK;
}
看下那个注册的详细实现,这个关系到inputDispatch怎么利用通道发布事件。
mService.mInputManager.registerInputChannel(mInputChannel,mInputWindowHandle);
这里的 mInputManager是InputManagerService,所以就到了:
InputManagerService.java
public voidregisterInputChannel(InputChannel inputChannel,
InputWindowHandleinputWindowHandle) {
nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle,false);
}
最终还是native层来实现的。
com_android_server_input_InputManagerService.cpp
static voidnativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj,jboolean monitor) {
//这里调用了InputDispatch(cpp)的registerInputChannel。
status_t status = im->registerInputChannel(
env, inputChannel,inputWindowHandle, monitor);
}
InputDispatcher.cpp
status_tInputDispatcher::registerInputChannel(const sp<InputChannel>&inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor){
//这里创建了 Connection,在它的构造函数中会实例化inputPublisher,并传参 inputChannel,其中InputDispatch会通过inputPublisher这个对象发布事件给inputChannel,
sp<Connection>connection = new Connection( inputChannel, inputWindowHandle, monitor);
}
InputTransport.cpp
InputPublisher把 inputChannel赋值给 mChannel,后面会通过这个 mChannel对象sendMessage。
InputPublisher::InputPublisher(const sp<InputChannel>&channel) :
mChannel(channel) {
}
把这些理清后,再回头看InputDispatch的事件分发就好明白了。
InputDispatcher.cpp
voidInputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>&inputTargets) {
prepareDispatchCycleLocked(currentTime,connection, eventEntry, &inputTarget);
}
voidInputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry,const InputTarget* inputTarget) {
enqueueDispatchEntriesLocked(currentTime,connection,
splitMotionEntry,inputTarget);
}
voidInputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry,const InputTarget* inputTarget) {
//把eventEntry转成dispatchEntry,并入队到
enqueueDispatchEntryLocked(connection,eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
//把队列的中事件分发出去,调用的是InputPublisher的publishKeyEvent函数。
startDispatchCycleLocked(currentTime,connection);
}
InputDispatcher.cpp
status_tInputPublisher::publishKeyEvent( uint32_t seq, int32_tdeviceId, int32_t
source, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
int32_tmetaState, int32_trepeatCount, nsecs_tdownTime, nsecs_t eventTime) {
InputMessage msg;
//看到了应用程序中keycode,keyAction等。
msg.header.type = InputMessage::TYPE_KEY;
msg.body.key.seq = seq;
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
msg.body.key.action = action;
msg.body.key.flags = flags;
msg.body.key.keyCode = keyCode;
msg.body.key.scanCode = scanCode;
msg.body.key.metaState = metaState;
msg.body.key.repeatCount = repeatCount;
msg.body.key.downTime = downTime;
msg.body.key.eventTime = eventTime;
//把inputmessage发送通道的服务端。
return mChannel->sendMessage(&msg);
}
到这里事件的发送就完了,接下来就是对事件的接收处理。