先看看notifyMotion方法,因为是从InputReader中传递过来的,并携带了NotifyMotionArgs
实体
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
...
// 日志输出
ALOGD("notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
"displayId=%" PRId32 ", policyFlags=0x%x, "
"action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
"edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
"yCursorPosition=%f, downTime=%" PRId64,
args->id, args->eventTime, args->deviceId, args->source, args->displayId,
args->policyFlags, args->action, args->actionButton, args->flags, args->metaState,
args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision,
args->xCursorPosition, args->yCursorPosition, args->downTime);
for (uint32_t i = 0; i < args->pointerCount; i++) {
ALOGD(" Pointer %d: id=%d, toolType=%d, "
"x=%f, y=%f, pressure=%f, size=%f, "
"touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
"orientation=%f",
i, args->pointerProperties[i].id, args->pointerProperties[i].toolType,
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
}
...
bool needWake;
...
// Just enqueue a new motion event.
// // 将传递过来的NotifyMotionArgs转换为MotionEntry对象
std::unique_ptr<MotionEntry> newEntry =
std::make_unique<MotionEntry>(args->id, args->eventTime, args->deviceId,
args->source, args->displayId, policyFlags,
args->action, args->actionButton, args->flags,
args->metaState, args->buttonState,
args->classification, args->edgeFlags,
args->xPrecision, args->yPrecision,
args->xCursorPosition, args->yCursorPosition,
args->downTime, args->pointerCount,
args->pointerProperties, args->pointerCoords, 0, 0);
// 目的为了把needWake变为true
needWake = enqueueInboundEventLocked(std::move(newEntry));
mLock.unlock();
} // release lock
if (needWake) {
// 初始化的时候就已经创建了一个单独的looper,这里通知looper中的线程唤醒
mLooper->wake();
}
}
好了,以上就是根据传递过来的NotifyMotionArgs对象,转换为MotionEntry对象,包含了EventEntry(存储的事件类型),并唤醒本身的looper线程,继续看看InputDispatcher中的线程
status_t InputDispatcher::start() {
if (mThread) {
return ALREADY_EXISTS;
}
mThread = std::make_unique<InputThread>(
"InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
return OK;
}
以上就是创建了InputThread线程,线程名称为InputDispatcher,继续看看dispatchOnce
void InputDispatcher::dispatchOnce() {
...
dispatchOnceInnerLocked(&nextWakeupTime);
...
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
具体看看dispatchOnceInnerLocked
函数
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
switch (mPendingEvent->type) {
...
case EventEntry::Type::KEY: {
...
done = dispatchKeyLocked(currentTime, keyEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::Type::MOTION: {
...
done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
break;
}
}
MotionEntry中保存了EventEntry,EventEntry中又保留了事件类型,根据传递类型属于MOTION,继续分析dispatchMotionLocked
函数
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
...
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
// 默认走这,找到一个合适的window:简言之就是遍历所有window,看触摸事件发生在哪个window上,找到该window
// window/TouchMonitors和输入事件进行了绑定
// TouchMonitors会有多个,代表了触摸到的所有window,每个有输入事件的window都有一个TouchMonitors
// injectionResult返回为真代表可以往window注入事件
injectionResult =
findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
&conflictingPointerActions);
}
...
// 如果injectionResult不为SUCCESS,则返回false不做事件分发,不会丢掉此次事件,下次再处理
if (injectionResult == InputEventInjectionResult::PENDING) {
return false;
}
// 如果返回值属于权限不足,则不做事件分发,丢掉此次的事件
if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) {
ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
return true;
}
// 如果injectionResult不为SUCCESS,则返回true不做事件分发,丢掉此次的事件
if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
CancelationOptions::Mode mode(isPointerEvent
? CancelationOptions::CANCEL_POINTER_EVENTS
: CancelationOptions::CANCEL_NON_POINTER_EVENTS);
CancelationOptions options(mode, "input event injection failed");
synthesizeCancelationEventsForMonitorsLocked(options);
return true;
}
// 事件分发,inputTargets代表了window窗口句柄,event是MotionEntry,属于InputDispatcher中单独封装的,包含了原始事件的转换
dispatchEventLocked(currentTime, entry, inputTargets);
首先会调用findTouchedWindowTargetsLocked
函数来遍历当前所有的window,找到发生输入事件的window,然后调用dispatchEventLocked
分发TouchMonitors,也就是为每个window分发输入事件,先分析以下两个函数
findTouchedWindowTargetsLocked
InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN ||
maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction);
// true,接下来事件都会保存在tempTouchState中
// 处理新手势,按下,因为手势都是从按下开始的
if (newGesture) {
bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
if (switchedDevice && tempTouchState.down && !down && !isHoverAction) {
ALOGI("Dropping event because a pointer for a different device is already down "
"in display %" PRId32,
displayId);
// TODO: test multiple simultaneous input streams.
injectionResult = InputEventInjectionResult::FAILED;
switchedDevice = false;
wrongDevice = true;
goto Failed;
}
tempTouchState.reset();
tempTouchState.down = down;
tempTouchState.deviceId = entry.deviceId;
tempTouchState.source = entry.source;
tempTouchState.displayId = displayId;
isSplit = false;
}
// 进入该分支
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
/* Case 1: New splittable pointer going down, or need target for hover or scroll. */
// 触摸时的坐标
int32_t x;
int32_t y;
int32_t pointerIndex = getMotionEventActionPointerIndex(action);
// 拿到点击事件的x,y
x = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));
y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
// true
bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
// 找到合适的window,WindowInfoHandle是一个代表应用程序窗口的结构体。
// 它包含一个窗口句柄、应用程序进程的PID和UID、窗口视图的屏幕矩形、窗口是否可见等信息
// 在找window的时候,会判断window是否有效,是否具有焦点,是否可见,若都满足,才会返回window
// 事件信息都临时保存在tempTouchState中
newTouchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
isDown /*addOutsideTargets*/, true /*addPortalWindows*/);
...
if (newTouchedWindowHandle != nullptr &&
mBlockUntrustedTouchesMode != BlockUntrustedTouchesMode::DISABLED) {
// 这个函数主要是处理遮挡window的情况,例如:
// 计算目标窗口是否遮挡了当前窗口,如果是,则该触摸区域不能传递给当前窗口处理,需要传递给目标窗口处理;
// 计算目标窗口是否遮挡了其他窗口,如果是,则需要递归地检查该窗口及其子窗口是否被遮挡;
// 逐层向上检查父窗口是否遮挡当前窗口,如果遮挡,则该触摸区域不能传递给当前窗口处理
// 需要传递给遮挡窗口的子窗口(或底层窗口)处理;
// 如果目标窗口与当前窗口重叠,则需要进行更精细的检查,以确定哪个窗口能够接收触摸事件。
TouchOcclusionInfo occlusionInfo =
computeTouchOcclusionInfoLocked(newTouchedWindowHandle, x, y);
if (!isTouchTrustedLocked(occlusionInfo)) {
if (DEBUG_TOUCH_OCCLUSION) {
ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
for (const auto& log : occlusionInfo.debugInfo) {
ALOGD("%s", log.c_str());
}
}
onUntrustedTouchLocked(occlusionInfo.obscuringPackage);
if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {
ALOGW("Dropping untrusted touch event due to %s/%d",
occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
newTouchedWindowHandle = nullptr;
}
}
}
// selectResponsiveMonitorsLocked方法:用于从当前所有的TouchedMonitor中筛选出只响应当前触摸事件的手势监控器
// TouchedMonitor,GestureMonitor
// findTouchedGestureMonitorsLocked:用于查找指定屏幕上被触摸的手势监控器。
// 该函数主要在处理触摸事件的分发过程中使用,以确定哪些手势监控器需要响应当前触摸事件
// 1.获取指定屏幕上被触摸的所有窗口,以及它们的窗口类型和窗口句柄;
// 2.逐个遍历所有窗口,针对每个手势监控器窗口,判断触摸坐标是否在窗口内部;
// 3.如果触摸坐标在窗口内部,则将该手势监控器加入到结果列表中;
// 4.最终将所有被触摸的手势监控器返回
// 以上步骤获取到了所有被触摸的TouchedMonitor,然后存入了newGestureMonitors中
// tempTouchState属于TouchState结构体,tempTouchState.portalWindows保存了触摸过的所有window
const std::vector<TouchedMonitor> newGestureMonitors = isDown
? selectResponsiveMonitorsLocked(
findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows))
: tempTouchState.gestureMonitors;
...
if (newTouchedWindowHandle != nullptr) {
...
// 将找到的窗口添加进tempTouchState(TouchState)
tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
}
// 为true,保存newGestureMonitors(每个触摸过的window都有一个TouchMonitors)到tempTouchState中
if (isDown) {
tempTouchState.addGestureMonitors(newGestureMonitors);
}
}
// 检查是否具有手势监控器,检查所有窗口中是否有前景窗口(必须有一个,不然事件该分发到谁身上?)
bool hasGestureMonitor = !tempTouchState.gestureMonitors.empty();
if (!haveForegroundWindow && !hasGestureMonitor) {
ALOGI("Dropping event because there is no touched foreground window in display "
"%" PRId32 " or gesture monitor to receive it.",displayId);
injectionResult = InputEventInjectionResult::FAILED;
goto Failed;
}
// 赋予注入权限,后面还会检查uid是否一致
injectionPermission = INJECTION_PERMISSION_GRANTED;
// 检查都通过,可以往window注入事件了
injectionResult = InputEventInjectionResult::SUCCEEDED;
// 处理tempTouchState里所包含的所有window,如果发现InputTarget为空则会为这个window创建一个
// 保存了window的屏幕尺寸,密度,inputChannel等信息,代表了window的token
for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
touchedWindow.pointerIds, inputTargets);
}
// 添加手势监视器,也就是将InputTarget中的inputChannel更新为monitor中的inputChannel
for (const TouchedMonitor& touchedMonitor : tempTouchState.gestureMonitors) {
addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset,
touchedMonitor.yOffset, inputTargets);
}
tempTouchState.filterNonAsIsTouchWindows();
//函数到这里就结束了,再往下就是failed代码块了
...
return injectionResult;
}
以上代码为判断是不是新手势 (从down按下开始),然后将触摸事件(哪块设备,哪块屏幕,是否属于down事件)保存到tempTouchState中,然后根据触摸的x,y坐标和displayId(哪块屏幕),去找到发生触摸事件的window(findTouchedWindowAtLocked
函数),返回值就是WindowInfoHandle
,代表着一个window,然后再去处理遮挡window的情况,如果发现目标窗口被父窗口遮挡了,那么事件会分发给父窗口,然后通过findTouchedGestureMonitorsLocked
去找到手势监控器,因为每个触摸过的window都有一个手势监控器,将手势监控器和window窗体都保存到tempTouchState中,再检查window权限是否可以将事件注入到该window上,若权限通过,则遍历tempTouchState
中保存的window将事件注入到该window上,再为每个Window创建InputTarget(代表输入事件的目标对象,代表了window窗口句柄)
,再将inputTarget
保存到inputTargets
集合中,然后遍历手势监控器,更新了一下inputChannel,先讲解以下函数:
findTouchedWindowAtLocked
sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x,
int32_t y, TouchState* touchState,
bool addOutsideTargets,
bool addPortalWindows,
bool ignoreDragWindow) {
// 获取当前屏幕的所有window
const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
// 遍历所有window
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
...
const WindowInfo* windowInfo = windowHandle->getInfo();
// window所在的屏幕是否和事件产生的屏幕一致
if (windowInfo->displayId == displayId) {
auto flags = windowInfo->flags;
// window必须可见
if (windowInfo->visible) {
// NOT_TOUCHABLE如果带有这个flag,则点击事件会被穿透到下一层window,本身window无法响应
// 例如toast弹窗(系统窗口),就是无法响应事件的
// 用于表示应用程序窗口是否接收触摸事件
if (!flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {//not_touchable
// 判断是否具有焦点
bool isTouchModal = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) &&
!flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL);
// 如果一个应用程序窗口被设置为NOT_TOUCHABLE标志,则它的touchableRegion将为空,
// 此时windowInfo->touchableRegionContainsPoint(x, y)方法将始终返回false。
// 否则,如果窗口是可触摸的,则windowInfo->touchableRegionContainsPoint(x, y)方法将检查坐标点(x, y)是否在touchableRegion中,
// 如果是,则返回true,否则返回false。
// 可以使用此方法来检查用户点击的位置是否在window的可触摸区域内,以便在处理用户输入事件时选择正确的窗口。
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
int32_t portalToDisplayId = windowInfo->portalToDisplayId;
if (portalToDisplayId != ADISPLAY_ID_NONE &&
portalToDisplayId != displayId) {
if (addPortalWindows) {
// For the monitoring channels of the display.
touchState->addPortalWindow(windowHandle);
}
return findTouchedWindowAtLocked(portalToDisplayId, x, y, touchState,
addOutsideTargets, addPortalWindows);
}
// Found window.返回window
return windowHandle;
}
}
// 如果WindowInfo的Flag字段包含了WATCH_OUTSIDE_TOUCH标志,则表示此window关注用户是否在窗口外部发生触摸事件。
// 当用户在窗口外部发生触摸事件时,系统将保持此窗口的焦点(focus)状态,并将发送一个ACTION_OUTSIDE类型的MotionEvent事件给此窗口,
// 以通知此窗口发生了外部触摸事件,例如dialog
if (addOutsideTargets && flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
touchState->addOrUpdateWindow(windowHandle,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
BitSet32(0));
}
}
}
}
return nullptr;
}
简单说就是通过以下几步来找到window:
NOT_TOUCHABLE
这个标志和是否具有焦点,来决定当前window是消费此事件,如果不消费,会将事件交给下一个window返回的windowHandle
对象就是窗口实体
findTouchedGestureMonitorsLocked
这个方法主要是为了找到InputTarget,即手势监控器,里面保存了触摸事件,一个window对应了一个手势监控器
std::vector<TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked(
int32_t displayId, const std::vector<sp<WindowInfoHandle>>& portalWindows) const {
std::vector<TouchedMonitor> touchedMonitors;
std::vector<Monitor> monitors = getValueByKey(mGestureMonitorsByDisplay, displayId);
addGestureMonitors(monitors, touchedMonitors);
// 遍历所有窗口
for (const sp<WindowInfoHandle>& portalWindow : portalWindows) {
const WindowInfo* windowInfo = portalWindow->getInfo();
//获取每个window的TouchedMonitor
monitors = getValueByKey(mGestureMonitorsByDisplay, windowInfo->portalToDisplayId);
// 将每个监视器(monitors)都存入touchedMonitors中
addGestureMonitors(monitors, touchedMonitors, -windowInfo->frameLeft,
-windowInfo->frameTop);
}
return touchedMonitors;
}
addOrUpdateWindow
void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags,
BitSet32 pointerIds) {
if (targetFlags & InputTarget::FLAG_SPLIT) {
split = true;
}
for (size_t i = 0; i < windows.size(); i++) {
TouchedWindow& touchedWindow = windows[i];
if (touchedWindow.windowHandle == windowHandle) {
touchedWindow.targetFlags |= targetFlags;
if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
}
touchedWindow.pointerIds.value |= pointerIds.value;
return;
}
}
TouchedWindow touchedWindow;
touchedWindow.windowHandle = windowHandle;
touchedWindow.targetFlags = targetFlags;
touchedWindow.pointerIds = pointerIds;
windows.push_back(touchedWindow);
}
可以看出来就是更新当前window或者新增window到windows中,代码位于TouchState.cpp中
addWindowTargetLocked
void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds,
std::vector<InputTarget>& inputTargets) {
// 找到window的句柄,也就是当前window,是可能为空的
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();
// 如果该对象为空(InputTarget代表输入事件的目标对象,通常是触摸屏、按键或手柄等外部设备的桥梁对象)
if (it == inputTargets.end()) {
InputTarget inputTarget;
std::shared_ptr<InputChannel> inputChannel =
getInputChannelLocked(windowHandle->getToken());
...
// 创建inputTarget对象,保存window和屏幕信息
// 并将该对象保存到inputTargets集合中
inputTarget.inputChannel = inputChannel;
inputTarget.flags = targetFlags;
inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
inputTarget.displayOrientation = windowInfo->displayOrientation;
inputTarget.displaySize =
int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight);
inputTargets.push_back(inputTarget);
it = inputTargets.end() - 1;
}
ALOG_ASSERT(it->flags == targetFlags);
ALOG_ASSERT(it->globalScaleFactor == windowInfo->globalScaleFactor);
// 将pointerIds和window绑定,pointerIds就是手指id
it->addPointers(pointerIds, windowInfo->transform);
}
至此,整个流程结束,目的都是为了找到window窗口,处理window窗口,返回injectionResult
,若为true,代表窗口可以注入事件,所以继续看看下一个阶段步骤dispatchEventLocked
dispatchEventLocked
此处进行事件分发,因为已经处理好了对应的window和权限相关
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
std::shared_ptr<EventEntry> eventEntry,
const std::vector<InputTarget>& inputTargets) {
...
// 向系统发送一个用户活动的信号,以防止在事件分发的时候设备进入休眠模式
pokeUserActivityLocked(*eventEntry);
for (const InputTarget& inputTarget : inputTargets) {
// 获得window连接
sp<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
if (connection != nullptr) {
//准备分发事件
prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
} ...
}
}
prepareDispatchCycleLocked
函数中会调用enqueueDispatchEntriesLocked
继续执行下一步逻辑
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
std::shared_ptr<EventEntry> eventEntry,
...
// 只有当事件输出队列为空的时候,才会开始分发
bool wasEmpty = connection->outboundQueue.empty();
// 生成DispatchEntry,再将**分发实体**存入outboundQueue队列中(输出的分发队列)
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.empty()) {
// 开始分发事件
startDispatchCycleLocked(currentTime, connection);
}
}
需要继续分析一下enqueueDispatchEntryLocked
和startDispatchCycleLocked
enqueueDispatchEntryLocked
void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget,
int32_t dispatchMode) {
...
// 根据inputTarget里面的屏幕信息以及eventEntry,构建出一个DispatchEntry
std::unique_ptr<DispatchEntry> dispatchEntry =
createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
dispatchEntry->resolvedAction = motionEntry.action;
dispatchEntry->resolvedEventId = motionEntry.id;
...
// 将分发实体存入outboundQueue队列中(输出的分发队列)
connection->outboundQueue.push_back(dispatchEntry.release());
startDispatchCycleLocked
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {//DispatchEntry
...
// 开始分发DispatchEntry实体事件,outboundQueue保存了EventEntry和屏幕信息,也就是DispatchEntry实体
while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
// 获得dispatchEntry
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
const std::chrono::nanoseconds timeout =
getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
// 设置超时相关
dispatchEntry->timeoutTime = currentTime + timeout.count();
// Publish the event.
status_t status;
// 从dispatchEntry拿到EventEntry
const EventEntry& eventEntry = *(dispatchEntry->eventEntry);
switch (eventEntry.type) {
...
case EventEntry::Type::MOTION: {//主要关心这个case
// 转换为MotionEntry,父子关系
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
...
// Publish the motion event.
// 发布event事件,将一个输入事件(通常是一个运动事件)发送到指定的应用程序
// 将屏幕信息,屏幕id,实体序列号,动作源事件(down),event状态(按下等状态),位于屏幕的xy坐标
// 手指数量,屏幕方向,传递给应用程序
status = 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->displayOrientation,
dispatchEntry->displaySize.x,
dispatchEntry->displaySize.y,
motionEntry.downTime, motionEntry.eventTime,
motionEntry.pointerCount,
motionEntry.pointerProperties, usingCoords);
break;
}
...
}
继续分析一下publishMotionEvent是怎么发送消息到上层的
frameworks/native/libs/input/InputTransport.cpp
// 屏幕信息,屏幕id,实体序列号,动作源事件(down),event状态(按下等状态),位于屏幕的xy坐标,手指数量,屏幕方向
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, uint32_t displayOrientation,
int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime,
uint32_t pointerCount, const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
...
// 将传递过来的信息DispatcherEntry转换为InputMessage对象
// 传递过来的信息属于DispatchEntry对象里的内容,DispatchEntry对象也就是存在outbound队列中待分发的事件信息
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.displayOrientation = displayOrientation;
msg.body.motion.displayWidth = displayWidth;
msg.body.motion.displayHeight = displayHeight;
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]);
}
// InputChannel 是用于实现输入事件通信的一种机制。
// 它提供了一个简单且可靠的方式,让应用程序或系统进程可以与InputDispatcher.cpp进行通信
// 向另一个端点发送消息。如果通道已满,则保证根本不会发送消息。在消费者发送完成信号后重试,表明它已从通道中消费了一些待处理的消息。
// 成功返回OK。
// 如果通道已满,则返回 WOULD_BLOCK。
// 如果通道的对等点已关闭,则返回 DEAD_OBJECT。
// 其他错误可能表示通道已损坏
return mChannel->sendMessage(&msg);
}
以上就上将InputDispatcher中生产的对象DispatcherEntry转换为最后待发送的InputMessage对象,通过InputChannel发送到上层,socket形式,InputChannel会通过socket向远端的socket发送消息
而InputChannel客户端会在activity的启动过程中会创建,在ViewRootImpl.java#setView中创建Java层的InputChannel对象mInputChannel(socket pair)并且创建了事件的监听new WindowInputEventReceiver(就会进入上层的事件分发)
。而InputChannel服务端会保存到WindowState的mInputChannel。所以view事件分发就是客户端发给服务端的一个流程
看看具体代码
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
// view测量,布局,绘制流程
requestLayout();
// 创建了客户端inputChannel
InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
inputChannel = new InputChannel();
}
// inputChannel客户端和服务端已经创建完成
// 底层会调用sendMessage发送事件给receiveMessage来收听事件
// 然后就会将事件上报给WindowInputEventReceiver监听
// 这里inputChannel还创建了事件的监听,由底层上报
if (inputChannel != null) {
...
// 事件监听的实现,交给上层view分发事件
mInputEventReceiver = new WindowInputEventReceiver(inputChannel,Looper.myLooper());
}
}