> 文章列表 > Android—IMS的InputDispatcher

Android—IMS的InputDispatcher

Android—IMS的InputDispatcher

前文说到InputReader调用mQueuedListener->flush()会去换下InputDispatcher的Looper然后处理输入事件

frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp:

bool InputDispatcherThread::threadLoop() {mDispatcher->dispatchOnce();return true;
}void InputDispatcher::dispatchOnce() {nsecs_t nextWakeupTime = LONG_LONG_MAX;{ // acquire lockstd::scoped_lock _l(mLock);mDispatcherIsAlive.notify_all();// Run a dispatch loop if there are no pending commands.// The dispatch loop might enqueue commands to run afterwards.if (!haveCommandsLocked()) {dispatchOnceInnerLocked(&nextWakeupTime);}// Run all pending commands if there are any.// If any commands were run then force the next poll to wake up immediately.if (runCommandsLockedInterruptible()) {nextWakeupTime = LONG_LONG_MIN;}} // release lock// Wait for callback or timeout or wake.  (make sure we round up, not down)nsecs_t currentTime = now();int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);mLooper->pollOnce(timeoutMillis);
}void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {....switch (mPendingEvent->type) {case EventEntry::TYPE_CONFIGURATION_CHANGED:....case EventEntry::TYPE_DEVICE_RESET: ....case EventEntry::TYPE_KEY: ....case EventEntry::TYPE_MOTION:{MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {dropReason = DROP_REASON_APP_SWITCH;}if (dropReason == DROP_REASON_NOT_DROPPED&& isStaleEvent(currentTime, typedEntry)) {dropReason = DROP_REASON_STALE;}if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {dropReason = DROP_REASON_BLOCKED;}done = dispatchMotionLocked(currentTime, typedEntry,&dropReason, nextWakeupTime);break;}default:ALOG_ASSERT(false);break;}if (done) {if (dropReason != DROP_REASON_NOT_DROPPED) {dropInboundEventLocked(mPendingEvent, dropReason);}mLastDropReason = dropReason;releasePendingEventLocked();*nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately}
}

我们主要看Motion屏幕输入事件的

bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {....bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;if (isPointerEvent) {// Pointer event.  (eg. touchscreen)injectionResult = findTouchedWindowTargetsLocked(currentTime,entry, inputTargets, nextWakeupTime, &conflictingPointerActions);} else {// Non touch event.  (eg. trackball)injectionResult = findFocusedWindowTargetsLocked(currentTime,entry, inputTargets, nextWakeupTime);}....// Dispatch the motion.dispatchEventLocked(currentTime, entry, inputTargets);return true;
}

1.findTouchedWindowTargetsLocked  寻找目标Window

2.WMS与IMS的联系

3.dispatchEventLocked 分发事件

1.findTouchedWindowTargetsLocked

int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,const MotionEntry& entry,std::vector<InputTarget>& inputTargets,nsecs_t* nextWakeupTime,bool* outConflictingPointerActions) {ATRACE_CALL();...// 读取触控事件所属的Display的id信息int32_t displayId = entry.displayId;...// 只有ACTION_DOWN类型代表新的触控事件,需要寻找新的目标窗口,后续的ACTION_MOVE或ACTION_UP类型的触控事件直接发送导已经找到的目标窗口bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN ||maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction);...if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {// 读取触控事件的x、y坐标位置int32_t x;int32_t y;if (isFromMouse) {...} else {x = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));}// 根据触控事件所属的displayid、x/y坐标位置等属性信息,调用findTouchedWindowAtLocked找到目标窗口sp<InputWindowHandle> newTouchedWindowHandle =findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,isDown /*addOutsideTargets*/, true /*addPortalWindows*/);...} else {...}...
}sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,int32_t x, int32_t y, bool addOutsideTargets, bool addPortalWindows) {// 从前到后遍历窗口找到被触摸的窗口。const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);for (const sp<InputWindowHandle>& windowHandle : windowHandles) {const InputWindowInfo* windowInfo = windowHandle->getInfo();if (windowInfo->displayId == displayId) {int32_t flags = windowInfo->layoutParamsFlags;if (windowInfo->visible) {if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {...// 根据触控事件的x/y坐标位置信息与窗口的可见区域进行匹配找到目标窗口if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {...return windowHandle;}}...}}}return nullptr;
}std::vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(int32_t displayId) const {// 从集合mWindowHandlesByDisplay中根据传入的displayId取出对应的可见窗口集合return getValueByKey(mWindowHandlesByDisplay, displayId);
}

所以findTouchedWindowTargetsLocked就是用DeviceId和触摸的坐标轴来找到对应Window,那mWindowHandlesByDisplay的窗口数据是从哪里来的?

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp:

void InputDispatcher::updateWindowHandlesForDisplayLocked(const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) {...// Insert or replacemWindowHandlesByDisplay[displayId] = newHandles;
}void InputDispatcher::setInputWindowsLocked(const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) {...updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId);...
}void InputDispatcher::setInputWindows(const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>& handlesPerDisplay) {{ // acquire lockstd::scoped_lock _l(mLock);for (auto const& i : handlesPerDisplay) {setInputWindowsLocked(i.second, i.first);}}...
}

frameworks\\base\\services\\core\\jni\\com_android_server_input_InputManagerService.cpp:

void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray,int32_t displayId) {std::vector<sp<InputWindowHandle> > windowHandles;if (windowHandleObjArray) {jsize length = env->GetArrayLength(windowHandleObjArray);for (jsize i = 0; i < length; i++) {jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);if (! windowHandleObj) {break; // found null element indicating end of used portion of the array}sp<InputWindowHandle> windowHandle =android_view_InputWindowHandle_getHandle(env, windowHandleObj);if (windowHandle != nullptr) {windowHandles.push_back(windowHandle);}env->DeleteLocalRef(windowHandleObj);}}mInputManager->getDispatcher()->setInputWindows(windowHandles, displayId);....
}static void nativeSetInputWindows(JNIEnv* env, jclass /* clazz */,jlong ptr, jobjectArray windowHandleObjArray) {NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);im->setInputWindows(env, windowHandleObjArray);
}

所以Java层可以调用IMS的nativeSetInputWindows方法给IMS设置窗口数据。

2.WMS与IMS的联系

在handleResumeActivity中,将 DecorView 添加到 WindowManager中,

wm.addView(decor, l);

frameworks\\base\\core\\java\\android\\view\\WindowManagerGlobal.java:

    public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {....root = new ViewRootImpl(view.getContext(), display);view.setLayoutParams(wparams);mViews.add(view);mRoots.add(root);mParams.add(wparams);// do this last because it fires off messages to start doing thingstry {root.setView(view, wparams, panelParentView);} catch (RuntimeException e) {// BadTokenException or InvalidDisplayException, clean up.if (index >= 0) {removeViewLocked(index, true);}throw e;}}}

frameworks\\base\\core\\java\\android\\view\\ViewRootImpl.java:

   public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {synchronized (this) {if (mView == null) {mView = view;......if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {mInputChannel = new InputChannel();}try {......res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(),mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,mAttachInfo.mOutsets, mInputChannel);} catch (RemoteException e) {......} finally {......}......if (mInputChannel != null) {if (mInputQueueCallback != null) {mInputQueue = new InputQueue();mInputQueueCallback.onInputQueueCreated(mInputQueue);}// 接收输入事件mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());}......}}}
  1. 在mWindowSession.addToDisplay中,会调用setInputWindows设置窗口数据。
  2. 创建了InputChannel用于接受输入事件。
  3. new WindowInputEventReceiver(mInputChannel, Looper.myLooper());接受处理事件。

mWindowSession.addToDisplay会调用WMS的addWindow,InputChannel是参数之一,把InputChannel传给了WMS。

frameworks\\base\\services\\core\\java\\com\\android\\server\\wm\\WindowManagerService.java:

    public int addWindow(Session session, IWindow client, int seq,LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,Rect outContentInsets, Rect outStableInsets, Rect outOutsets,DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,InsetsState outInsetsState) {....final boolean openInputChannels = (outInputChannel != null&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);if  (openInputChannels) {win.openInputChannel(outInputChannel);}....}

frameworks\\base\\services\\core\\java\\com\\android\\server\\wm\\WindowState.java:

    void openInputChannel(InputChannel outInputChannel) {if (mInputChannel != null) {throw new IllegalStateException("Window already has an input channel.");}String name = getName();InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);mInputChannel = inputChannels[0];mClientChannel = inputChannels[1];mInputWindowHandle.token = mClient.asBinder();if (outInputChannel != null) {mClientChannel.transferTo(outInputChannel);mClientChannel.dispose();mClientChannel = null;} else {// If the window died visible, we setup a dummy input channel, so that taps// can still detected by input monitor channel, and we can relaunch the app.// Create dummy event receiver that simply reports all events as handled.mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);}mWmService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder());}

frameworks\\base\\core\\java\\android\\view\\InputChannel.java:

    public static InputChannel[] openInputChannelPair(String name) {if (name == null) {throw new IllegalArgumentException("name must not be null");}if (DEBUG) {Slog.d(TAG, "Opening input channel pair '" + name + "'");}return nativeOpenInputChannelPair(name);}

frameworks\\base\\core\\jni\\android_view_InputChannel.cpp:

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,jclass clazz, jstring nameObj) {ScopedUtfChars nameChars(env, nameObj);std::string name = nameChars.c_str();sp<InputChannel> serverChannel;sp<InputChannel> clientChannel;status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);if (result) {String8 message;message.appendFormat("Could not open input channel pair.  status=%d", result);jniThrowRuntimeException(env, message.string());return NULL;}jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);if (env->ExceptionCheck()) {return NULL;}jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,std::make_unique<NativeInputChannel>(serverChannel));if (env->ExceptionCheck()) {return NULL;}jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,std::make_unique<NativeInputChannel>(clientChannel));if (env->ExceptionCheck()) {return NULL;}env->SetObjectArrayElement(channelPair, 0, serverChannelObj);env->SetObjectArrayElement(channelPair, 1, clientChannelObj);return channelPair;
}

frameworks\\native\\libs\\input\\InputTransport.cpp:

status_t InputChannel::openInputChannelPair(const std::string& name,sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {int sockets[2];if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {status_t result = -errno;ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",name.c_str(), errno);outServerChannel.clear();outClientChannel.clear();return result;}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));std::string serverChannelName = name;serverChannelName += " (server)";outServerChannel = new InputChannel(serverChannelName, sockets[0]);std::string clientChannelName = name;clientChannelName += " (client)";outClientChannel = new InputChannel(clientChannelName, sockets[1]);return OK;
}

openInputChannel里面创建一对InputChannel,然后将Server端的InputChannel注册到InputDispatcher中,将Client端的InputChannel返回给客户端即ViewRootImpl使用。InputChannel封装了name和fd。通过文件描述符fd实现进程通信。

3.dispatchEventLocked 分发事件

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) {....for (const InputTarget& inputTarget : inputTargets) {ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);if (connectionIndex >= 0) {sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);}....}
}ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {if (inputChannel == nullptr) {return -1;}for (size_t i = 0; i < mConnectionsByFd.size(); i++) {sp<Connection> connection = mConnectionsByFd.valueAt(i);if (connection->inputChannel->getToken() == inputChannel->getToken()) {return i;}}return -1;
}

getConnectionIndexLocked通过inputChannel获取Connection对象。

所以说dispatchEventLocked会获取窗口对应的inputChannel,并调用prepareDispatchCycleLocked进行处理。 prepareDispatchCycleLocked方法内部调用了enqueueDispatchEntriesLocked方法,后续通过inputChannel传输事件。

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {....// Not splitting.  Enqueue dispatch entries for the event as is.enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {bool wasEmpty = connection->outboundQueue.isEmpty();// Enqueue dispatch entries for the requested modes.enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_OUTSIDE);enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_IS);enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);// If the outbound queue was previously empty, start the dispatch cycle going.if (wasEmpty && !connection->outboundQueue.isEmpty()) {startDispatchCycleLocked(currentTime, connection);}
}

1.enqueueDispatchEntryLocked将事件插入队列

2.startDispatchCycleLocked开始分发事件

1.enqueueDispatchEntryLocked将事件插入队列

void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,int32_t dispatchMode) {....// This is a new event.// Enqueue a new dispatch entry onto the outbound queue for this connection.DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments refinputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,inputTarget->globalScaleFactor, inputTarget->windowXScale,inputTarget->windowYScale);// Apply target flags and update the connection's input state.switch (eventEntry->type) {case EventEntry::TYPE_KEY: {KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);dispatchEntry->resolvedAction = keyEntry->action;dispatchEntry->resolvedFlags = keyEntry->flags;if (!connection->inputState.trackKey(keyEntry,dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",connection->getInputChannelName().c_str());
#endifdelete dispatchEntry;return; // skip the inconsistent event}break;}case EventEntry::TYPE_MOTION: {MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;} else {dispatchEntry->resolvedAction = motionEntry->action;}if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE&& !connection->inputState.isHovering(motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) {
#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event",connection->getInputChannelName().c_str());
#endifdispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;}dispatchEntry->resolvedFlags = motionEntry->flags;if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;}if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) {dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;}if (!connection->inputState.trackMotion(motionEntry,dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event",connection->getInputChannelName().c_str());
#endifdelete dispatchEntry;return; // skip the inconsistent event}dispatchPointerDownOutsideFocus(motionEntry->source,dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken());break;}}// Remember that we are waiting for this dispatch to complete.if (dispatchEntry->hasForegroundTarget()) {incrementPendingForegroundDispatches(eventEntry);}// Enqueue the dispatch entry.connection->outboundQueue.enqueueAtTail(dispatchEntry);traceOutboundQueueLength(connection);}

enqueueDispatchEntryLocked里面将输入事件重新封装为一个DispatchEntry,根据不同的Event填充数据,然后放到connection的outboundQueue队列中。

2.startDispatchCycleLocked开始分发事件

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection) {while (connection->status == Connection::STATUS_NORMAL&& !connection->outboundQueue.isEmpty()) {DispatchEntry* dispatchEntry = connection->outboundQueue.head;dispatchEntry->deliveryTime = currentTime;// Publish the event.status_t status;EventEntry* eventEntry = dispatchEntry->eventEntry;switch (eventEntry->type) {case EventEntry::TYPE_KEY: {KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);// Publish the key event.status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,keyEntry->deviceId, keyEntry->source, keyEntry->displayId,dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,keyEntry->keyCode, keyEntry->scanCode,keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,keyEntry->eventTime);break;}case EventEntry::TYPE_MOTION: {MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);PointerCoords scaledCoords[MAX_POINTERS];const PointerCoords* usingCoords = motionEntry->pointerCoords;// Set the X and Y offset depending on the input source.float xOffset, yOffset;if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)&& !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {float globalScaleFactor = dispatchEntry->globalScaleFactor;float wxs = dispatchEntry->windowXScale;float wys = dispatchEntry->windowYScale;xOffset = dispatchEntry->xOffset * wxs;yOffset = dispatchEntry->yOffset * wys;if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) {for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {scaledCoords[i] = motionEntry->pointerCoords[i];scaledCoords[i].scale(globalScaleFactor, wxs, wys);}usingCoords = scaledCoords;}} else {xOffset = 0.0f;yOffset = 0.0f;// We don't want the dispatch target to know.if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {scaledCoords[i].clear();}usingCoords = scaledCoords;}}// Publish the motion event.status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,motionEntry->deviceId, motionEntry->source, motionEntry->displayId,dispatchEntry->resolvedAction, motionEntry->actionButton,dispatchEntry->resolvedFlags, motionEntry->edgeFlags,motionEntry->metaState, motionEntry->buttonState, motionEntry->classification,xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,motionEntry->downTime, motionEntry->eventTime,motionEntry->pointerCount, motionEntry->pointerProperties,usingCoords);break;}default:ALOG_ASSERT(false);return;}// Check the result.if (status) {if (status == WOULD_BLOCK) {if (connection->waitQueue.isEmpty()) {ALOGE("channel '%s' ~ Could not publish event because the pipe is full. ""This is unexpected because the wait queue is empty, so the pipe ""should be empty and we shouldn't have any problems writing an ""event to it, status=%d", connection->getInputChannelName().c_str(),status);abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);} else {// Pipe is full and we are waiting for the app to finish process some events// before sending more events to it.
#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ Could not publish event because the pipe is full, ""waiting for the application to catch up",connection->getInputChannelName().c_str());
#endifconnection->inputPublisherBlocked = true;}} else {ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, ""status=%d", connection->getInputChannelName().c_str(), status);abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);}return;}// Re-enqueue the event on the wait queue.connection->outboundQueue.dequeue(dispatchEntry);traceOutboundQueueLength(connection);connection->waitQueue.enqueueAtTail(dispatchEntry);traceWaitQueueLength(connection);}
}

startDispatchCycleLocked会根据事件类型选择inputPublisher.publishKeyEvent和inputPublisher.publishMotionEvent,这两个方法将事件写入InputChannel通道中。这样ViewRootImpl端的InputChannel就可以通过socket获取到事件信息,然后在WindowInputEventReceiver中将事件传递到DecorView最后传到对应的View上。

在发送完毕后会将事件移出connection->outboundQueue队列,并放入到waitQueue等待队列中,等待事件处理完毕后再移出。

总结:ViewRootImpl的setView中,会调用WMS.addWindow,会先创建一对InputChannel,给到ViewRootImpl和IMS,InputChannel是由通过文件描述符fd创建的,并通过fd实现两个服务的进程通信。在InputDispatcher被唤醒后,InputDispatcher会遍历窗口数据,找到对应窗口的InputChannel,根据事件类型key或者motion封装输入事件,然后将事件通过InputChannel发送给WindowInputEventReceiver中处理,最后发送到对应的View中