status_t InputDispatcher::start() {
if (mThread) {
return ALREADY_EXISTS;
}
mThread = std::make_unique<InputThread>(
"InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
return OK;
}
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LLONG_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()) {
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 = LLONG_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 == LLONG_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);
}
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) {
resetKeyRepeatLocked();
}
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
if (mDispatchFrozen) {
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;
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()) {
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();
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;
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::CONFIGURATION_CHANGED: {
const ConfigurationChangedEntry& typedEntry =
static_cast<const ConfigurationChangedEntry&>(*mPendingEvent);
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
dropReason = DropReason::NOT_DROPPED; // configuration changes are never dropped
break;
}
case EventEntry::Type::DEVICE_RESET: {
const DeviceResetEntry& typedEntry =
static_cast<const DeviceResetEntry&>(*mPendingEvent);
done = dispatchDeviceResetLocked(currentTime, typedEntry);
dropReason = DropReason::NOT_DROPPED; // device resets are never dropped
break;
}
case EventEntry::Type::FOCUS: {
std::shared_ptr<FocusEntry> typedEntry =
std::static_pointer_cast<FocusEntry>(mPendingEvent);
dispatchFocusLocked(currentTime, typedEntry);
done = true;
dropReason = DropReason::NOT_DROPPED; // focus events are never dropped
break;
}
case EventEntry::Type::TOUCH_MODE_CHANGED: {
const auto typedEntry = std::static_pointer_cast<TouchModeEntry>(mPendingEvent);
dispatchTouchModeChangeLocked(currentTime, typedEntry);
done = true;
dropReason = DropReason::NOT_DROPPED; // touch mode events are never dropped
break;
}
case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
const auto typedEntry =
std::static_pointer_cast<PointerCaptureChangedEntry>(mPendingEvent);
dispatchPointerCaptureChangedLocked(currentTime, typedEntry, dropReason);
done = true;
break;
}
case EventEntry::Type::DRAG: {
std::shared_ptr<DragEntry> typedEntry =
std::static_pointer_cast<DragEntry>(mPendingEvent);
dispatchDragLocked(currentTime, typedEntry);
done = true;
break;
}
case EventEntry::Type::KEY: {
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);
break;
}
case EventEntry::Type::MOTION: {
std::shared_ptr<MotionEntry> motionEntry =
std::static_pointer_cast<MotionEntry>(mPendingEvent);
if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
dropReason = DropReason::APP_SWITCH;
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::Type::SENSOR: {
std::shared_ptr<SensorEntry> sensorEntry =
std::static_pointer_cast<SensorEntry>(mPendingEvent);
if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
dropReason = DropReason::APP_SWITCH;
}
// Sensor timestamps use SYSTEM_TIME_BOOTTIME time base, so we can't use
// 'currentTime' here, get SYSTEM_TIME_BOOTTIME instead.
nsecs_t bootTime = systemTime(SYSTEM_TIME_BOOTTIME);
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(bootTime, *sensorEntry)) {
dropReason = DropReason::STALE;
}
dispatchSensorLocked(currentTime, sensorEntry, &dropReason, nextWakeupTime);
done = true;
break;
}
}
if (done) {
if (dropReason != DropReason::NOT_DROPPED) {
dropInboundEventLocked(*mPendingEvent, dropReason);
}
mLastDropReason = dropReason;
releasePendingEventLocked();
*nextWakeupTime = LLONG_MIN; // force next poll to wake up immediately
}
}
dispatchOnceInnerLocked()函数的实现解释了以下几个问题:
□如果派发队列为空,则会使派发线程陷入无限期休眠状态。
□即将被派发的事件从派发队列中取出并保存在mPendingEvent成员变量中。
□事件有可能因为某些原因而被丢弃,被丢弃的原因保存在dropReason中。
□不同类型的事件使用不同的派发函数进行实际的派发动作。如本例中的Motion事件使用dispatchMotionLocked()函数进行派发。
□派发一个事件至少需要一次线程循环才能完成。是否在下次循环继续尝试此事件的派发由派发函数的返回值决定。
□事件的派发是串行的,在排在队首的事件完成派发或被丢弃之前,不会对后续的事件进行派发。理解InputDispatcher的这一特点非常重要。
bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<MotionEntry> entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
ATRACE_CALL();
// Preprocessing.
if (!entry->dispatchInProgress) {
entry->dispatchInProgress = true;
logOutboundMotionDetails("dispatchMotion - ", *entry);
}
// Clean up if dropping the event.
if (*dropReason != DropReason::NOT_DROPPED) {
setInjectionResult(*entry,
*dropReason == DropReason::POLICY ? InputEventInjectionResult::SUCCEEDED
: InputEventInjectionResult::FAILED);
return true;
}
const bool isPointerEvent = isFromSource(entry->source, AINPUT_SOURCE_CLASS_POINTER);
// Identify targets.
std::vector<InputTarget> inputTargets;
bool conflictingPointerActions = false;
InputEventInjectionResult injectionResult;
if (isPointerEvent) {// 如果是坐标事件
// Pointer event. (eg. touchscreen)
if (mDragState &&
(entry->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN) {
// If drag and drop ongoing and pointer down occur: pilfer drag window pointers
pilferPointersLocked(mDragState->dragWindow->getToken());
}
inputTargets =
findTouchedWindowTargetsLocked(currentTime, *entry, &conflictingPointerActions,
/*byref*/ injectionResult);
LOG_ALWAYS_FATAL_IF(injectionResult != InputEventInjectionResult::SUCCEEDED &&
!inputTargets.empty());
} else {
// Non touch event. (eg. trackball) // key事件直接找焦点窗口
sp<WindowInfoHandle> focusedWindow =
findFocusedWindowTargetLocked(currentTime, *entry, nextWakeupTime, injectionResult);
if (injectionResult == InputEventInjectionResult::SUCCEEDED) {
LOG_ALWAYS_FATAL_IF(focusedWindow == nullptr);
addWindowTargetLocked(focusedWindow,
InputTarget::Flags::FOREGROUND |
InputTarget::Flags::DISPATCH_AS_IS,
/*pointerIds=*/{}, getDownTime(*entry), inputTargets);
}
}
if (injectionResult == InputEventInjectionResult::PENDING) {
return false;
}
setInjectionResult(*entry, injectionResult);
if (injectionResult == InputEventInjectionResult::TARGET_MISMATCH) {
return true;
}
if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
CancelationOptions::Mode mode(
isPointerEvent ? CancelationOptions::Mode::CANCEL_POINTER_EVENTS
: CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS);
CancelationOptions options(mode, "input event injection failed");
synthesizeCancelationEventsForMonitorsLocked(options);
return true;
}
// Add monitor channels from event's or focused display.
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
// Dispatch the motion.
if (conflictingPointerActions) {
CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
"conflicting pointer actions");
synthesizeCancelationEventsForAllConnectionsLocked(options);
}
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
dispatchMotionLocked 首先查找inputTarget
然后将inputTarget进行分发
其中InputTarget的数据结构
struct InputTarget {
enum class Flags : uint32_t {
/* This flag indicates that the event is being delivered to a foreground application. */
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. */
WINDOW_IS_OBSCURED = 1 << 1,
/* This flag indicates that a motion event is being split across multiple windows. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
DISPATCH_AS_SLIPPERY_ENTER = 1 << 13,
/* 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. */
WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
};
/* Mask for all dispatch modes. */
static constexpr const ftl::Flags<InputTarget::Flags> DISPATCH_MASK =
ftl::Flags<InputTarget::Flags>() | Flags::DISPATCH_AS_IS | Flags::DISPATCH_AS_OUTSIDE |
Flags::DISPATCH_AS_HOVER_ENTER | Flags::DISPATCH_AS_HOVER_EXIT |
Flags::DISPATCH_AS_SLIPPERY_EXIT | Flags::DISPATCH_AS_SLIPPERY_ENTER;
// The input channel to be targeted.
std::shared_ptr<InputChannel> inputChannel;
// Flags for the input target.
ftl::Flags<Flags> flags;
// 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.
std::bitset<MAX_POINTER_ID + 1> pointerIds;
// Event time for the first motion event (ACTION_DOWN) dispatched to this input target if
// FLAG_SPLIT is set.
std::optional<nsecs_t> firstDownTimeInTarget;
// 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(std::bitset<MAX_POINTER_ID + 1> 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
根据坐标查找inputTarget
std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked(
nsecs_t currentTime, const MotionEntry& entry, bool* outConflictingPointerActions,
InputEventInjectionResult& outInjectionResult) {
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
/* Case 1: New splittable pointer going down, or need target for hover or scroll. */
const auto [x, y] = resolveTouchedPosition(entry);
const int32_t pointerIndex = getMotionEventActionPointerIndex(action);
// Outside targets should be added upon first dispatched DOWN event. That means, this should
// be a pointer that would generate ACTION_DOWN, *and* touch should not already be down.
const bool isStylus = isPointerFromStylus(entry, pointerIndex);
auto [newTouchedWindowHandle, outsideTargets] =
findTouchedWindowAtLocked(displayId, x, y, isStylus);
InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, float x, float y, bool isStylus,
bool ignoreDragWindow) const {
// Traverse windows from front to back to find touched window.
std::vector<InputTarget> outsideTargets;
const auto& windowHandles = getWindowHandlesLocked(displayId);
// 遍历所有的窗口信息
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) {
continue;
}
const WindowInfo& info = *windowHandle->getInfo();
if (!info.isSpy() &&
windowAcceptsTouchAt(info, displayId, x, y, isStylus, getTransformLocked(displayId))) {
return {windowHandle, outsideTargets};
}
if (info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) {
addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_OUTSIDE,
/*pointerIds=*/{}, /*firstDownTimeInTarget=*/std::nullopt,
outsideTargets);
}
}
return {nullptr, {}};
}
该函数遍历所有窗口,寻找可以接收输入事件的窗口,需要满足以下条件:
1)当前窗口必须是可见的。
2)当前窗口不能包含InputWindowInfo::Flag::NOT_TOUCHABLE,设置了这个flag的窗口不能接收Motion事件。
3)当前输入事件的坐标落在当前窗口的Motion区域里,那么返回当前窗口。
特殊情况是:如果当前窗口包含InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH,那么直接调用TouchState.addOrUpdateWindow将当前窗口添加到tempTouchState中,但是这个窗口无法接收到完整的down/move/up手势,只会在down的时候接收到一次MotionEvent.ACTION_OUTSIDE事件。
最后,再通过TouchState.addOrUpdateWindow()将newTouchedWindowHandle带着这些设置的flag添加到tempTouchState中:
void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHandle,
ftl::Flags<InputTarget::Flags> targetFlags,
std::bitset<MAX_POINTER_ID + 1> pointerIds,
std::optional<nsecs_t> firstDownTimeInTarget,
std::vector<InputTarget>& inputTargets) const {
std::vector<InputTarget>::iterator it =
std::find_if(inputTargets.begin(), inputTargets.end(),
[&windowHandle](const InputTarget& inputTarget) {
return inputTarget.inputChannel->getConnectionToken() ==
windowHandle->getToken();
});
const WindowInfo* windowInfo = windowHandle->getInfo();
if (it == inputTargets.end()) {
std::optional<InputTarget> target =
createInputTargetLocked(windowHandle, targetFlags, firstDownTimeInTarget);
if (!target) {
return;
}
inputTargets.push_back(*target);
it = inputTargets.end() - 1;
}
ALOG_ASSERT(it->flags == targetFlags);
ALOG_ASSERT(it->globalScaleFactor == windowInfo->globalScaleFactor);
it->addPointers(pointerIds, windowInfo->transform);
}
根据焦点窗口查找inputTarget
根据焦点查找目标窗口是由findFocusedWindowTargetLocked()函数完成的。这个函数的主要工作与findTouchedWindowTargetsLocked()函数一样,而且其窗口查找过程毫不费力。因为InputDispatcher有一个名为mFocusedWindowHandle的InputWindowHandle对象,所以InputDispatcher只要判断此对象是否为NULL即可。WMS在进行布局操作时,会根据处于焦点状态的Activity、窗口的属性与ZOrder确定处于焦点状态的窗口,并随同窗口列表一起提交至InputDispatcher。
sp<WindowInfoHandle> InputDispatcher::findFocusedWindowTargetLocked(
nsecs_t currentTime, const EventEntry& entry, nsecs_t* nextWakeupTime,
InputEventInjectionResult& outInjectionResult) {
std::string reason;
outInjectionResult = InputEventInjectionResult::FAILED; // Default result
int32_t displayId = getTargetDisplayId(entry);
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 nullptr;
}
// Drop key events if requested by input feature
if (focusedWindowHandle != nullptr && shouldDropInput(entry, focusedWindowHandle)) {
return nullptr;
}
// 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.
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;
outInjectionResult = InputEventInjectionResult::PENDING;
return nullptr;
} 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 nullptr;
} else {
// Still waiting for the focused window
outInjectionResult = InputEventInjectionResult::PENDING;
return nullptr;
}
}
// 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());
outInjectionResult = InputEventInjectionResult::TARGET_MISMATCH;
return nullptr;
}
if (focusedWindowHandle->getInfo()->inputConfig.test(
WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str());
outInjectionResult = InputEventInjectionResult::PENDING;
return nullptr;
}
// 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.
if (entry.type == EventEntry::Type::KEY) {
if (shouldWaitToSendKeyLocked(currentTime, focusedWindowHandle->getName().c_str())) {
*nextWakeupTime = *mKeyIsWaitingForEventsTimeout;
outInjectionResult = InputEventInjectionResult::PENDING;
return nullptr;
}
}
outInjectionResult = InputEventInjectionResult::SUCCEEDED;
return focusedWindowHandle;
}
sp<WindowInfoHandle> InputDispatcher::getFocusedWindowHandleLocked(int displayId) const {
sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(displayId);
return getWindowHandleLocked(focusedToken, displayId);
}
分发事件到查找到的inputTarget
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);
for (const InputTarget& inputTarget : inputTargets) {
std::shared_ptr<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
if (connection != nullptr) {
prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
} 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());
}
}
}
}
根据inputchannel找到 connection
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const std::shared_ptr<Connection>& connection,
std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget) {
if (ATRACE_ENABLED()) {
std::string message =
StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=0x%" PRIx32 ")",
connection->getInputChannelName().c_str(), eventEntry->id);
ATRACE_NAME(message.c_str());
}
if (DEBUG_DISPATCH_CYCLE) {
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=%s, "
"globalScaleFactor=%f, pointerIds=%s %s",
connection->getInputChannelName().c_str(), inputTarget.flags.string().c_str(),
inputTarget.globalScaleFactor, bitsetToString(inputTarget.pointerIds).c_str(),
inputTarget.getPointerInfoString().c_str());
}
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::Status::NORMAL) {
if (DEBUG_DISPATCH_CYCLE) {
ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
connection->getInputChannelName().c_str(),
ftl::enum_string(connection->status).c_str());
}
return;
}
// Split a motion event if needed.
if (inputTarget.flags.test(InputTarget::Flags::SPLIT)) {
LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION,
"Entry type %s should not have Flags::SPLIT",
ftl::enum_string(eventEntry->type).c_str());
const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
if (!inputTarget.firstDownTimeInTarget.has_value()) {
logDispatchStateLocked();
LOG(FATAL) << "Splitting motion events requires a down time to be set for the "
"target on connection "
<< connection->getInputChannelName() << " for "
<< originalMotionEntry.getDescription();
}
std::unique_ptr<MotionEntry> splitMotionEntry =
splitMotionEvent(originalMotionEntry, inputTarget.pointerIds,
inputTarget.firstDownTimeInTarget.value());
if (!splitMotionEntry) {
return; // split event was dropped
}
if (splitMotionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {
std::string reason = std::string("reason=pointer cancel on split window");
android_log_event_list(LOGTAG_INPUT_CANCEL)
<< connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS;
}
if (DEBUG_FOCUS) {
ALOGD("channel '%s' ~ Split motion event.",
connection->getInputChannelName().c_str());
logOutboundMotionDetails(" ", *splitMotionEntry);
}
enqueueDispatchEntriesLocked(currentTime, connection, std::move(splitMotionEntry),
inputTarget);
return;
}
}
// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const std::shared_ptr<Connection>& connection,
std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget) {
if (ATRACE_ENABLED()) {
std::string message =
StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, id=0x%" PRIx32 ")",
connection->getInputChannelName().c_str(), eventEntry->id);
ATRACE_NAME(message.c_str());
}
LOG_ALWAYS_FATAL_IF(!inputTarget.flags.any(InputTarget::DISPATCH_MASK),
"No dispatch flags are set for %s", eventEntry->getDescription().c_str());
const bool wasEmpty = connection->outboundQueue.empty();
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::Flags::DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::Flags::DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::Flags::DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::Flags::DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.empty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connection>& connection,
std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget,
ftl::Flags<InputTarget::Flags> dispatchMode) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf("enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)",
connection->getInputChannelName().c_str(),
dispatchMode.string().c_str());
ATRACE_NAME(message.c_str());
}
ftl::Flags<InputTarget::Flags> inputTargetFlags = inputTarget.flags;
if (!inputTargetFlags.any(dispatchMode)) {
return;
}
inputTargetFlags.clear(InputTarget::DISPATCH_MASK);
inputTargetFlags |= dispatchMode;
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
std::unique_ptr<DispatchEntry> dispatchEntry =
createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);
// Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
// different EventEntry than what was passed in.
EventEntry& newEntry = *(dispatchEntry->eventEntry);
// Apply target flags and update the connection's input state.
switch (newEntry.type) {
case EventEntry::Type::KEY: {
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(newEntry);
dispatchEntry->resolvedEventId = keyEntry.id;
dispatchEntry->resolvedAction = keyEntry.action;
dispatchEntry->resolvedFlags = keyEntry.flags;
if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags)) {
if (DEBUG_DISPATCH_CYCLE) {
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key "
"event",
connection->getInputChannelName().c_str());
}
return; // skip the inconsistent event
}
break;
}
case EventEntry::Type::MOTION: {
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(newEntry);
// Assign a default value to dispatchEntry that will never be generated by InputReader,
// and assign a InputDispatcher value if it doesn't change in the if-else chain below.
constexpr int32_t DEFAULT_RESOLVED_EVENT_ID =
static_cast<int32_t>(IdGenerator::Source::OTHER);
dispatchEntry->resolvedEventId = DEFAULT_RESOLVED_EVENT_ID;
if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
} else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_HOVER_EXIT)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
} else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_HOVER_ENTER)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
} else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
} else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
} else {
dispatchEntry->resolvedAction = motionEntry.action;
dispatchEntry->resolvedEventId = motionEntry.id;
}
if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
!connection->inputState.isHovering(motionEntry.deviceId, motionEntry.source,
motionEntry.displayId)) {
if (DEBUG_DISPATCH_CYCLE) {
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover "
"enter event",
connection->getInputChannelName().c_str());
}
// We keep the 'resolvedEventId' here equal to the original 'motionEntry.id' because
// this is a one-to-one event conversion.
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
}
dispatchEntry->resolvedFlags = motionEntry.flags;
if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_CANCEL) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_CANCELED;
}
if (dispatchEntry->targetFlags.test(InputTarget::Flags::WINDOW_IS_OBSCURED)) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
}
if (dispatchEntry->targetFlags.test(InputTarget::Flags::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_CYCLE) {
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion "
"event",
connection->getInputChannelName().c_str());
}
return; // skip the inconsistent event
}
dispatchEntry->resolvedEventId =
dispatchEntry->resolvedEventId == DEFAULT_RESOLVED_EVENT_ID
? mIdGenerator.nextId()
: motionEntry.id;
if (ATRACE_ENABLED() && dispatchEntry->resolvedEventId != motionEntry.id) {
std::string message = StringPrintf("Transmute MotionEvent(id=0x%" PRIx32
") to MotionEvent(id=0x%" PRIx32 ").",
motionEntry.id, dispatchEntry->resolvedEventId);
ATRACE_NAME(message.c_str());
}
if ((motionEntry.flags & AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) &&
(motionEntry.policyFlags & POLICY_FLAG_TRUSTED)) {
// Skip reporting pointer down outside focus to the policy.
break;
}
dispatchPointerDownOutsideFocus(motionEntry.source, dispatchEntry->resolvedAction,
inputTarget.inputChannel->getConnectionToken());
break;
}
case EventEntry::Type::FOCUS:
case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::POINTER_CAPTURE_CHANGED:
case EventEntry::Type::DRAG: {
break;
}
case EventEntry::Type::SENSOR: {
LOG_ALWAYS_FATAL("SENSOR events should not go to apps via input channel");
break;
}
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("%s events should not go to apps",
ftl::enum_string(newEntry.type).c_str());
break;
}
}
// Remember that we are waiting for this dispatch to complete.
if (dispatchEntry->hasForegroundTarget()) {
incrementPendingForegroundDispatches(newEntry);
}
// Enqueue the dispatch entry.
connection->outboundQueue.push_back(dispatchEntry.release());
traceOutboundQueueLength(*connection);
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const std::shared_ptr<Connection>& connection) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf("startDispatchCycleLocked(inputChannel=%s)",
connection->getInputChannelName().c_str());
ATRACE_NAME(message.c_str());
}
if (DEBUG_DISPATCH_CYCLE) {
ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str());
}
while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
const std::chrono::nanoseconds timeout = getDispatchingTimeoutLocked(connection);
dispatchEntry->timeoutTime = currentTime + timeout.count();
// Publish the event.
status_t status;
const EventEntry& eventEntry = *(dispatchEntry->eventEntry);
switch (eventEntry.type) {
case EventEntry::Type::KEY: {
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry);
std::array<uint8_t, 32> hmac = getSignature(keyEntry, *dispatchEntry);
if (DEBUG_OUTBOUND_EVENT_DETAILS) {
LOG(DEBUG) << "Publishing " << *dispatchEntry << " to "
<< connection->getInputChannelName();
}
// Publish the key event.
status = connection->inputPublisher
.publishKeyEvent(dispatchEntry->seq,
dispatchEntry->resolvedEventId, keyEntry.deviceId,
keyEntry.source, keyEntry.displayId,
std::move(hmac), dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags, keyEntry.keyCode,
keyEntry.scanCode, keyEntry.metaState,
keyEntry.repeatCount, keyEntry.downTime,
keyEntry.eventTime);
break;
}
case EventEntry::Type::MOTION: {
if (DEBUG_OUTBOUND_EVENT_DETAILS) {
LOG(DEBUG) << "Publishing " << *dispatchEntry << " to "
<< connection->getInputChannelName();
}
status = publishMotionEvent(*connection, *dispatchEntry);
break;
}
case EventEntry::Type::FOCUS: {
const FocusEntry& focusEntry = static_cast<const FocusEntry&>(eventEntry);
status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq,
focusEntry.id,
focusEntry.hasFocus);
break;
}
case EventEntry::Type::TOUCH_MODE_CHANGED: {
const TouchModeEntry& touchModeEntry =
static_cast<const TouchModeEntry&>(eventEntry);
status = connection->inputPublisher
.publishTouchModeEvent(dispatchEntry->seq, touchModeEntry.id,
touchModeEntry.inTouchMode);
break;
}
case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
const auto& captureEntry =
static_cast<const PointerCaptureChangedEntry&>(eventEntry);
status = connection->inputPublisher
.publishCaptureEvent(dispatchEntry->seq, captureEntry.id,
captureEntry.pointerCaptureRequest.enable);
break;
}
case EventEntry::Type::DRAG: {
const DragEntry& dragEntry = static_cast<const DragEntry&>(eventEntry);
status = connection->inputPublisher.publishDragEvent(dispatchEntry->seq,
dragEntry.id, dragEntry.x,
dragEntry.y,
dragEntry.isExiting);
break;
}
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET:
case EventEntry::Type::SENSOR: {
LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events",
ftl::enum_string(eventEntry.type).c_str());
return;
}
}
// Check the result.
if (status) {
if (status == WOULD_BLOCK) {
if (connection->waitQueue.empty()) {
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=%s(%d)",
connection->getInputChannelName().c_str(), statusToString(status).c_str(),
status);
abortBrokenDispatchCycleLocked(currentTime, connection, /*notify=*/true);
} 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_CYCLE) {
ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
"waiting for the application to catch up",
connection->getInputChannelName().c_str());
}
}
} else {
ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
"status=%s(%d)",
connection->getInputChannelName().c_str(), statusToString(status).c_str(),
status);
abortBrokenDispatchCycleLocked(currentTime, connection, /*notify=*/true);
}
return;
}
// Re-enqueue the event on the wait queue.
connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
connection->outboundQueue.end(),
dispatchEntry));
traceOutboundQueueLength(*connection);
connection->waitQueue.push_back(dispatchEntry);
if (connection->responsive) {
mAnrTracker.insert(dispatchEntry->timeoutTime,
connection->inputChannel->getConnectionToken());
}
traceWaitQueueLength(*connection);
}
}
status_t InputDispatcher::publishMotionEvent(Connection& connection,
DispatchEntry& dispatchEntry) const {
const EventEntry& eventEntry = *(dispatchEntry.eventEntry);
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
PointerCoords scaledCoords[MAX_POINTERS];
const PointerCoords* usingCoords = motionEntry.pointerCoords;
// Set the X and Y offset and X and Y scale depending on the input source.
if ((motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) &&
!(dispatchEntry.targetFlags.test(InputTarget::Flags::ZERO_COORDS))) {
float globalScaleFactor = dispatchEntry.globalScaleFactor;
if (globalScaleFactor != 1.0f) {
for (uint32_t i = 0; i < motionEntry.pointerCount; i++) {
scaledCoords[i] = motionEntry.pointerCoords[i];
// Don't apply window scale here since we don't want scale to affect raw
// coordinates. The scale will be sent back to the client and applied
// later when requesting relative coordinates.
scaledCoords[i].scale(globalScaleFactor, /*windowXScale=*/1, /*windowYScale=*/1);
}
usingCoords = scaledCoords;
}
} else if (dispatchEntry.targetFlags.test(InputTarget::Flags::ZERO_COORDS)) {
// We don't want the dispatch target to know the coordinates
for (uint32_t i = 0; i < motionEntry.pointerCount; i++) {
scaledCoords[i].clear();
}
usingCoords = scaledCoords;
}
std::array<uint8_t, 32> hmac = getSignature(motionEntry, dispatchEntry);
// Publish the motion event.
return connection.inputPublisher
.publishMotionEvent(dispatchEntry.seq, dispatchEntry.resolvedEventId,
motionEntry.deviceId, motionEntry.source, motionEntry.displayId,
std::move(hmac), dispatchEntry.resolvedAction,
motionEntry.actionButton, dispatchEntry.resolvedFlags,
motionEntry.edgeFlags, motionEntry.metaState,
motionEntry.buttonState, motionEntry.classification,
dispatchEntry.transform, motionEntry.xPrecision,
motionEntry.yPrecision, motionEntry.xCursorPosition,
motionEntry.yCursorPosition, dispatchEntry.rawTransform,
motionEntry.downTime, motionEntry.eventTime,
motionEntry.pointerCount, motionEntry.pointerProperties,
usingCoords);
}
status_t InputPublisher::publishMotionEvent(
uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
int32_t edgeFlags, int32_t metaState, int32_t buttonState,
MotionClassification classification, const ui::Transform& transform, float xPrecision,
float yPrecision, float xCursorPosition, float yCursorPosition,
const ui::Transform& rawTransform, nsecs_t downTime, nsecs_t eventTime,
uint32_t pointerCount, const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf("publishMotionEvent(inputChannel=%s, action=%s)",
mChannel->getName().c_str(),
MotionEvent::actionToString(action).c_str());
ATRACE_NAME(message.c_str());
}
if (verifyEvents()) {
mInputVerifier.processMovement(deviceId, action, pointerCount, pointerProperties,
pointerCoords, flags);
}
if (debugTransportPublisher()) {
std::string transformString;
transform.dump(transformString, "transform", " ");
ALOGD("channel '%s' publisher ~ %s: seq=%u, id=%d, deviceId=%d, source=%s, "
"displayId=%" PRId32 ", "
"action=%s, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
"metaState=0x%x, buttonState=0x%x, classification=%s,"
"xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
"pointerCount=%" PRIu32 " \n%s",
mChannel->getName().c_str(), __func__, seq, eventId, deviceId,
inputEventSourceToString(source).c_str(), displayId,
MotionEvent::actionToString(action).c_str(), actionButton, flags, edgeFlags,
metaState, buttonState, motionClassificationToString(classification), xPrecision,
yPrecision, downTime, eventTime, pointerCount, transformString.c_str());
}
if (!seq) {
ALOGE("Attempted to publish a motion event with sequence number 0.");
return BAD_VALUE;
}
if (pointerCount > MAX_POINTERS || pointerCount < 1) {
ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".",
mChannel->getName().c_str(), pointerCount);
return BAD_VALUE;
}
InputMessage msg;
msg.header.type = InputMessage::Type::MOTION;
msg.header.seq = seq;
msg.body.motion.eventId = eventId;
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
msg.body.motion.displayId = displayId;
msg.body.motion.hmac = std::move(hmac);
msg.body.motion.action = action;
msg.body.motion.actionButton = actionButton;
msg.body.motion.flags = flags;
msg.body.motion.edgeFlags = edgeFlags;
msg.body.motion.metaState = metaState;
msg.body.motion.buttonState = buttonState;
msg.body.motion.classification = classification;
msg.body.motion.dsdx = transform.dsdx();
msg.body.motion.dtdx = transform.dtdx();
msg.body.motion.dtdy = transform.dtdy();
msg.body.motion.dsdy = transform.dsdy();
msg.body.motion.tx = transform.tx();
msg.body.motion.ty = transform.ty();
msg.body.motion.xPrecision = xPrecision;
msg.body.motion.yPrecision = yPrecision;
msg.body.motion.xCursorPosition = xCursorPosition;
msg.body.motion.yCursorPosition = yCursorPosition;
msg.body.motion.dsdxRaw = rawTransform.dsdx();
msg.body.motion.dtdxRaw = rawTransform.dtdx();
msg.body.motion.dtdyRaw = rawTransform.dtdy();
msg.body.motion.dsdyRaw = rawTransform.dsdy();
msg.body.motion.txRaw = rawTransform.tx();
msg.body.motion.tyRaw = rawTransform.ty();
msg.body.motion.downTime = downTime;
msg.body.motion.eventTime = eventTime;
msg.body.motion.pointerCount = pointerCount;
for (uint32_t i = 0; i < pointerCount; i++) {
msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
}
return mChannel->sendMessage(&msg);
}
接下来通过inputChannel连接到ViewRootImpl中