1 InputReader的加工类型
InputReader具有多种加工类型,由上面的InputReader的执行流程可知,对于按键事件,InputReader会将按键信息封装成NotifyKeyArgs对象,并交给KeyboardInputMapper进行处理,最后调用notifyKey函数唤醒InputDispatcher所在的InputThread线程。如下图所示:
其中用于保存按键事件信息的结构体NotifyKeyArgs继承自NotifyArgs
frameworks/native/services/inputflinger/include/InputListener.h
/* Superclass of all input event argument objects */
struct NotifyArgs {
int32_t id;
nsecs_t eventTime;
inline NotifyArgs() : id(0), eventTime(0) {}
inline explicit NotifyArgs(int32_t id, nsecs_t eventTime) : id(id), eventTime(eventTime) {}
virtual ~NotifyArgs() { }
virtual void notify(InputListenerInterface& listener) const = 0;
};
InputReader加工的所有的事件类型存储结构体都继承自NotifyArgs,也都在InputListener.h头文件中定义。
该头文件中定义了8种事件类型,说明InputReader对原始事件加工之后,会得出8中事件类型,每一种事件类型有不同的处理方式。每种事件类型处理之后可能需要分发到窗口,可能不需要分发,如果需要分发则会调用InputDispatcher进行分发处理,如下图所示:
2 InputDispatcher分发流程
还是以按键事件为例,当按键事件需要分发时,会唤醒InputDispatcher线程
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
...
needWake = enqueueInboundEventLocked(std::move(newEntry));
mLock.unlock();
} // release lock
if (needWake) {
mLooper->wake();
}
}
InputDispatcher被唤醒之后,会调用threadLoop函数,初始化的时候,该函数中执行的函数被指定为dispatchOnce
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
status_t InputDispatcher::start() {
if (mThread) {
return ALREADY_EXISTS;
}
mThread = std::make_unique<InputThread>(
"InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
return OK;
}
dispatchOnce函数如下
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
std::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()) { //1
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 (runCommandsLockedInterruptable()) {
nextWakeupTime = LONG_LONG_MIN;
}
// If we are still waiting for ack on some events,
// we might have to wake up earlier to check if an app is anr'ing.
const nsecs_t nextAnrCheck = processAnrsLocked();
nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
// We are about to enter an infinitely long sleep, because we have no commands or
// pending or queued events
if (nextWakeupTime == LONG_LONG_MAX) {
mDispatcherEnteredIdle.notify_all();
}
} // 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);
}
注释1处会检查缓存队列中是否有还未处理的命令,如果没有就会立即执行下面的dispatchOnceInnerLocked函数进行分发。后面会获取当前时间,并计算下此唤醒的时间,最后调用pollOnce让InputDispatcher线程陷入沉睡,当有事件来临时由InputReader唤醒。
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
// Reset the key repeat timer whenever normal dispatch is suspended while the
// device is in a non-interactive state. This is to ensure that we abort a key
// repeat if the device is just coming out of sleep.
if (!mDispatchEnabled) { //1
resetKeyRepeatLocked();
}
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
if (mDispatchFrozen) { //2
if (DEBUG_FOCUS) {
ALOGD("Dispatch frozen. Waiting some more.");
}
return;
}
// Optimize latency of app switches.
// Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
// been pressed. When it expires, we preempt dispatch and drop all other pending events.
bool isAppSwitchDue = mAppSwitchDueTime <= currentTime; //3
if (mAppSwitchDueTime < *nextWakeupTime) {
*nextWakeupTime = mAppSwitchDueTime;
}
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (!mPendingEvent) {
if (mInboundQueue.empty()) { //4
if (isAppSwitchDue) {
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
resetPendingAppSwitchLocked(false);
isAppSwitchDue = false;
}
// Synthesize a key repeat if appropriate.
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
} else {
if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// Nothing to do if there is no pending event.
if (!mPendingEvent) {
return;
}
} else {
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.front(); //5
mInboundQueue.pop_front();
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(*mPendingEvent);
}
}
// Now we have an event to dispatch.
// All events are eventually dequeued and processed this way, even if we intend to drop them.
ALOG_ASSERT(mPendingEvent != nullptr);
bool done = false;
DropReason dropReason = DropReason::NOT_DROPPED; //6
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
dropReason = DropReason::POLICY;
} else if (!mDispatchEnabled) {
dropReason = DropReason::DISABLED;
}
if (mNextUnblockedEvent == mPendingEvent) {
mNextUnblockedEvent = nullptr;
}
switch (mPendingEvent->type) {
...
case EventEntry::Type::KEY: { //7
std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent);
if (isAppSwitchDue) {
if (isAppSwitchKeyEvent(*keyEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DropReason::NOT_DROPPED) {
dropReason = DropReason::APP_SWITCH;
}
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *keyEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
done = dispatchKeyLocked(currentTime, keyEntry, &dropReason, nextWakeupTime);//8
break;
}
...
if (done) { //9
if (dropReason != DropReason::NOT_DROPPED) {
dropInboundEventLocked(*mPendingEvent, dropReason);
}
mLastDropReason = dropReason;
releasePendingEventLocked(); //10
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
dispatchOnceInnerLocked主要做了这几件事情
-
InputDispatcher的冻结流程
注释1和2处用于判断InputDispatcher的状态,有三种状态,禁用、冻结和正常状态。 -
窗口切换操作处理
注释3处是为了优化应用切换时的延时,这里的mAppSwitchDueTime表示的是窗口切换的最迟分发时间,如果这个事件小于当前的系统时间,说明窗口切换事件没有得到及时的响应,会将nextWakeupTime赋值为mAppSwitchDueTime这个时间,表示当前的任务处理完之后立刻处理窗口切换事件。 -
取出事件
注释4处判断如果没有没有待处理的任务,就会在注释5处从缓存队列mInboundQueue中获取一个事件,如果mInboundQueue为空则返回。取出的事件放置到mPendingEvent中,这是EventEntry类型的指针。 -
事件丢弃
注释6处根据规则设置事件的丢弃规则,注释7处则根据具体的事件类型来设置事件的丢弃规则,默认值为不丢弃DropReason::NOT_DROPPED。如果不丢弃则会调用dispatchKeyLocked执行具体的分发工作。 -
后续处理
事件分发完成后,会在注释10处释放该次处理事件的对象。然后会将nextWakeupTime设置成LONG_LONG_MIN,以便快速的响应下次事件分发处理。
注释8处调用dispatchKeyLocked进行分发工作
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
if (!entry->dispatchInProgress) { //1
if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN &&
(entry->policyFlags & POLICY_FLAG_TRUSTED) &&
(!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) {
if (mKeyRepeatState.lastKeyEntry &&
mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode &&
// We have seen two identical key downs in a row which indicates that the device
// driver is automatically generating key repeats itself. We take note of the
// repeat here, but we disable our own next key repeat timer since it is clear that
// we will not need to synthesize key repeats ourselves.
mKeyRepeatState.lastKeyEntry->deviceId == entry->deviceId) {
// Make sure we don't get key down from a different device. If a different
// device Id has same key pressed down, the new device Id will replace the
// current one to hold the key repeat with repeat count reset.
// In the future when got a KEY_UP on the device id, drop it and do not
// stop the key repeat on current device.
entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1;
resetKeyRepeatLocked();
mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves
} else {
// Not a repeat. Save key down state in case we do see a repeat later.
resetKeyRepeatLocked();
mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout;
}
mKeyRepeatState.lastKeyEntry = entry;
} else if (entry->action == AKEY_EVENT_ACTION_UP && mKeyRepeatState.lastKeyEntry &&
mKeyRepeatState.lastKeyEntry->deviceId != entry->deviceId) {
// The key on device 'deviceId' is still down, do not stop key repeat
if (DEBUG_INBOUND_EVENT_DETAILS) {
ALOGD("deviceId=%d got KEY_UP as stale", entry->deviceId);
}
} else if (!entry->syntheticRepeat) {
resetKeyRepeatLocked();
}
if (entry->repeatCount == 1) {
entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
} else {
entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS;
}
entry->dispatchInProgress = true;
logOutboundKeyDetails("dispatchKey - ", *entry);
}
// Handle case where the policy asked us to try again later last time.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
if (currentTime < entry->interceptKeyWakeupTime) {
if (entry->interceptKeyWakeupTime < *nextWakeupTime) {
*nextWakeupTime = entry->interceptKeyWakeupTime;
}
return false; // wait until next wakeup
}
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
entry->interceptKeyWakeupTime = 0;
}
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
sp<IBinder> focusedWindowToken =
mFocusResolver.getFocusedWindowToken(getTargetDisplayId(*entry));
auto command = [this, focusedWindowToken, entry]() REQUIRES(mLock) {
doInterceptKeyBeforeDispatchingCommand(focusedWindowToken, *entry);
};
postCommandLocked(std::move(command));
return false; // wait for the command to run
} else {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
}
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
if (*dropReason == DropReason::NOT_DROPPED) {
*dropReason = DropReason::POLICY;
}
}
// Clean up if dropping the event.
if (*dropReason != DropReason::NOT_DROPPED) { //2
setInjectionResult(*entry,
*dropReason == DropReason::POLICY ? InputEventInjectionResult::SUCCEEDED
: InputEventInjectionResult::FAILED);
mReporter->reportDroppedKey(entry->id);
return true;
}
// Identify targets.
std::vector<InputTarget> inputTargets; //3
InputEventInjectionResult injectionResult =
findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime); //4
if (injectionResult == InputEventInjectionResult::PENDING) {
return false;
}
setInjectionResult(*entry, injectionResult);
if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
return true;
}
// Add monitor channels from event's or focused display.
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry)); //5
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets); //6
return true;
}
注释1处是一个标记,进入分发过程,该标记会被置为true。注释2处是判断是否被丢弃,对于被丢弃的事件,不做处理,并返回true。注释3处的InputTarget是存储窗口信息的。注释4寻找目标窗口,并将结果存储在injectionResult中,如果结果是InputEventInjectionResult::PENDING,表明目标窗口找到但是未响应而挂起,直接返回false。如果是不是InputEventInjectionResult::SUCCEEDED表明没找到目标窗口,未完成分发,直接返回true。
注释5处会将分发的目标添加到inputTargets中,并在注释6处将事件分发给inputTargets列表中的目标。
frameworks/native/services/inputflinger/dispatcher/InputTarget.h
/*
* An input target specifies how an input event is to be dispatched to a particular window
* including the window's input channel, control flags, a timeout, and an X / Y offset to
* be added to input event coordinates to compensate for the absolute position of the
* window area.
*/
struct InputTarget {
enum {
/* This flag indicates that the event is being delivered to a foreground application. */
FLAG_FOREGROUND = 1 << 0,
/* This flag indicates that the MotionEvent falls within the area of the target
* obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
FLAG_WINDOW_IS_OBSCURED = 1 << 1,
/* This flag indicates that a motion event is being split across multiple windows. */
FLAG_SPLIT = 1 << 2,
/* This flag indicates that the pointer coordinates dispatched to the application
* will be zeroed out to avoid revealing information to an application. This is
* used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing
* the same UID from watching all touches. */
FLAG_ZERO_COORDS = 1 << 3,
/* This flag indicates that the event should be sent as is.
* Should always be set unless the event is to be transmuted. */
FLAG_DISPATCH_AS_IS = 1 << 8,
/* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
* of the area of this target and so should instead be delivered as an
* AMOTION_EVENT_ACTION_OUTSIDE to this target. */
FLAG_DISPATCH_AS_OUTSIDE = 1 << 9,
/* This flag indicates that a hover sequence is starting in the given window.
* The event is transmuted into ACTION_HOVER_ENTER. */
FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10,
/* This flag indicates that a hover event happened outside of a window which handled
* previous hover events, signifying the end of the current hover sequence for that
* window.
* The event is transmuted into ACTION_HOVER_ENTER. */
FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11,
/* This flag indicates that the event should be canceled.
* It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips
* outside of a window. */
FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12,
/* This flag indicates that the event should be dispatched as an initial down.
* It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips
* into a new window. */
FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13,
/* Mask for all dispatch modes. */
FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS | FLAG_DISPATCH_AS_OUTSIDE |
FLAG_DISPATCH_AS_HOVER_ENTER | FLAG_DISPATCH_AS_HOVER_EXIT |
FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_ENTER,
/* This flag indicates that the target of a MotionEvent is partly or wholly
* obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */
FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
};
// The input channel to be targeted.
std::shared_ptr<InputChannel> inputChannel;
// Flags for the input target.
int32_t flags = 0;
// Scaling factor to apply to MotionEvent as it is delivered.
// (ignored for KeyEvents)
float globalScaleFactor = 1.0f;
// Current display transform. Used for compatibility for raw coordinates.
ui::Transform displayTransform;
// The subset of pointer ids to include in motion events dispatched to this input target
// if FLAG_SPLIT is set.
BitSet32 pointerIds;
// The data is stored by the pointerId. Use the bit position of pointerIds to look up
// Transform per pointerId.
ui::Transform pointerTransforms[MAX_POINTERS];
void addPointers(BitSet32 pointerIds, const ui::Transform& transform);
void setDefaultPointerTransform(const ui::Transform& transform);
/**
* Returns whether the default pointer information should be used. This will be true when the
* InputTarget doesn't have any bits set in the pointerIds bitset. This can happen for monitors
* and non splittable windows since we want all pointers for the EventEntry to go to this
* target.
*/
bool useDefaultPointerTransform() const;
/**
* Returns the default Transform object. This should be used when useDefaultPointerTransform is
* true.
*/
const ui::Transform& getDefaultPointerTransform() const;
std::string getPointerInfoString() const;
};
InputTarget这个结构体主要是分为了两部分,枚举中的是与目标窗口相关的一些标记,后面的是与目标窗口交互的一些参数,比如这里的inputChannel,它实际上是一个SocketPair,SocketPair用于进程间双向通信,这非常适合inputDispatcher与目标窗口之间的通信,因为inputDispatcher不仅要将事件分发到目标窗口,同时inputDispatcher也需要得到目标窗口对事件的响应。
寻找焦点窗口代码在findFocusedWindowTargetsLocked函数中
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked(
nsecs_t currentTime, const EventEntry& entry, std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime) {
std::string reason;
//获取输入事件的display id,由于Android支持多屏设备,这里获取输入事件在哪个屏幕,默认值0
int32_t displayId = getTargetDisplayId(entry);
//根据displayId获取WindowInfoHandle,存储的是窗口信息
sp<WindowInfoHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId);
//获取焦点应用的信息
std::shared_ptr<InputApplicationHandle> focusedApplicationHandle =
getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
// If there is no currently focused window and no focused application
// then drop the event.
//如果没有焦点窗口并且也没有焦点应用,则丢弃事件
if (focusedWindowHandle == nullptr && focusedApplicationHandle == nullptr) {
ALOGI("Dropping %s event because there is no focused window or focused application in "
"display %" PRId32 ".",
ftl::enum_string(entry.type).c_str(), displayId);
return InputEventInjectionResult::FAILED;
}
// Drop key events if requested by input feature
//如果有焦点窗口,但是输入系统要求丢弃,则丢弃
if (focusedWindowHandle != nullptr && shouldDropInput(entry, focusedWindowHandle)) {
return InputEventInjectionResult::FAILED;
}
// Compatibility behavior: raise ANR if there is a focused application, but no focused window.
// Only start counting when we have a focused event to dispatch. The ANR is canceled if we
// start interacting with another application via touch (app switch). This code can be removed
// if the "no focused window ANR" is moved to the policy. Input doesn't know whether
// an app is expected to have a focused window.
//焦点串口为空,但是焦点应用不为空,则提高ANR的概率。根据mNoFocusedWindowTimeoutTime值来判断是丢弃事件还是继续等待是否有焦点窗口。
if (focusedWindowHandle == nullptr && focusedApplicationHandle != nullptr) {
if (!mNoFocusedWindowTimeoutTime.has_value()) {
// We just discovered that there's no focused window. Start the ANR timer
std::chrono::nanoseconds timeout = focusedApplicationHandle->getDispatchingTimeout(
DEFAULT_INPUT_DISPATCHING_TIMEOUT);
mNoFocusedWindowTimeoutTime = currentTime + timeout.count();
mAwaitedFocusedApplication = focusedApplicationHandle;
mAwaitedApplicationDisplayId = displayId;
ALOGW("Waiting because no window has focus but %s may eventually add a "
"window when it finishes starting up. Will wait for %" PRId64 "ms",
mAwaitedFocusedApplication->getName().c_str(), millis(timeout));
*nextWakeupTime = *mNoFocusedWindowTimeoutTime;
return InputEventInjectionResult::PENDING;
} else if (currentTime > *mNoFocusedWindowTimeoutTime) {
// Already raised ANR. Drop the event
ALOGE("Dropping %s event because there is no focused window",
ftl::enum_string(entry.type).c_str());
return InputEventInjectionResult::FAILED;
} else {
// Still waiting for the focused window
return InputEventInjectionResult::PENDING;
}
}
// we have a valid, non-null focused window
//重置超时时间和等待的焦点应用
resetNoFocusedWindowTimeoutLocked();
// Verify targeted injection.
if (const auto err = verifyTargetedInjection(focusedWindowHandle, entry); err) {
ALOGW("Dropping injected event: %s", (*err).c_str());
return InputEventInjectionResult::TARGET_MISMATCH;
}
if (focusedWindowHandle->getInfo()->inputConfig.test(
WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str());
return InputEventInjectionResult::PENDING;
}
// If the event is a key event, then we must wait for all previous events to
// complete before delivering it because previous events may have the
// side-effect of transferring focus to a different window and we want to
// ensure that the following keys are sent to the new window.
//
// Suppose the user touches a button in a window then immediately presses "A".
// If the button causes a pop-up window to appear then we want to ensure that
// the "A" key is delivered to the new pop-up window. This is because users
// often anticipate pending UI changes when typing on a keyboard.
// To obtain this behavior, we must serialize key events with respect to all
// prior input events.
//对于按键事件,必须先处理其他的事件,因为可能会存在窗口切换的操作,由于UI的未及时更新,导致按键事件分配的错误,通常是希望等窗口切换完成后分发到新的窗口中。
if (entry.type == EventEntry::Type::KEY) {
if (shouldWaitToSendKeyLocked(currentTime, focusedWindowHandle->getName().c_str())) {
*nextWakeupTime = *mKeyIsWaitingForEventsTimeout;
return InputEventInjectionResult::PENDING;
}
}
// Success! Output targets.
//成功找到窗口,将其添加到inputTargets中
addWindowTargetLocked(focusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,
BitSet32(0), inputTargets);
// Done.
return InputEventInjectionResult::SUCCEEDED;
}
这个函数的作用就是找到焦点窗口,并将其添加到INputTargets中,实际的分发在dispatchKeyLocked函数的最后调用的dispatchEventLocked函数中,可以看出整体的逻辑都在dispatchKeyLocked函数中,首先找到焦点窗口然后将事件分发到焦点窗口。
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
std::shared_ptr<EventEntry> eventEntry,
const std::vector<InputTarget>& inputTargets) {
ATRACE_CALL();
if (DEBUG_DISPATCH_CYCLE) {
ALOGD("dispatchEventToCurrentInputTargets");
}
updateInteractionTokensLocked(*eventEntry, inputTargets);
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(*eventEntry);
//遍历inputTargets
for (const InputTarget& inputTarget : inputTargets) {
//根据InputTarget内部的inpuChannel获取Connection对象
sp<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken());//1
if (connection != nullptr) {
//开始事件发送循环
prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);//2
} else {
if (DEBUG_FOCUS) {
ALOGD("Dropping event delivery to target with channel '%s' because it "
"is no longer registered with the input dispatcher.",
inputTarget.inputChannel->getName().c_str());
}
}
}
}
遍历inputTargets列表,取出的每一个都是InputTarget结构体类型的对象,存储的是事件与窗口的交互信息。然后在注释1处根据inputChannel获取Connection对象,Connection可以理解为InputDispatcher与目标窗口的链接,内部包含了连接的状态、InputChannel等信息。注释2处调用prepareDispatchCycleLocked函数来开始事件的发送,最终是通过InputTarget中的inputChannel来和窗口进行进程间通信的。大致的流程是prepareDispatchCycleLocked调用enqueueDispatchEntriesLocked将输入事件入队列,如果队列不为空则调用startDispatchCycleLocked分发输入事件,在startDispatchCycleLocked函数中,会调用相应的publish相关方法,发布输入事件,实际是调用InputPublisher类中的publish***函数进行事件的分发,在这些函数中,最终都会调用InputChannel中的sendMessage函数分发事件, 在这个函数中通过socket与目标窗口进行通信。
大致的流程如下所示: