1 InputDispatcher代码解析第一部分
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
//条件编译指令
#if DEBUG_INBOUND_EVENT_DETAILS
if (args->action != AMOTION_EVENT_ACTION_MOVE) {
//当前动作不是AMOTION_EVENT_ACTION_MOVE
ALOGD("Cnt:%d 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->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN) ||
((args->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN))
? (mMotionCntByDisplay[args->displayId] == INT_MAX
? INT_MAX : (mMotionCntByDisplay[args->displayId]++))
: -1,
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));
}
}
#endif
//验证是否是有效motion事件
if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount,
args->pointerProperties)) {
return;
}
uint32_t policyFlags = args->policyFlags;
//定义InputReader上来的事件是值得信任的
policyFlags |= POLICY_FLAG_TRUSTED;
android::base::Timer t;
//事件入队前通过策略是java端(InputManagerService)进行拦截
mPolicy->interceptMotionBeforeQueueing(args->displayId, args->eventTime, /*byref*/ policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
std::to_string(t.duration().count()).c_str());
}
bool needWake;
{ // acquire lock
mLock.lock();
//判断事件是否需要过滤 可以通过setInputFilterEnabled设置
if (shouldSendMotionToInputFilterLocked(args)) {
mLock.unlock();
MotionEvent event;
event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
args->action, args->actionButton, args->flags, args->edgeFlags,
args->metaState, args->buttonState, args->classification, 1 /*xScale*/,
1 /*yScale*/, 0 /* xOffset */, 0 /* yOffset */, args->xPrecision,
args->yPrecision, args->xCursorPosition, args->yCursorPosition,
args->downTime, args->eventTime, args->pointerCount,
args->pointerProperties, args->pointerCoords);
//添加过滤flag
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
//policy消费了当次事件
return; // event was consumed by the filter
}
mLock.lock();
}
// Just enqueue a new motion event.
//构建触摸事件
MotionEntry* newEntry =
new 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);
//进入dispatcher的队列等待dispatcher处理派发
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
if (needWake) {
//派发队列来事件了,唤醒InputDispatcher
mLooper->wake();
}
}
1 根据inputReader上来的数据参数action判断如果不是AMOTION_EVENT_ACTION_MOVE
打印inputReader上报上来的数据信息,如果涉及多指
会遍历每一个触控点数据打印。
2 验证是否是有效事件
3 设置事件是值得信任的
4 事件进入队列前通过dispatchPolicy进行事件拦截
5 判断事件是否需要过滤需要就添加POLICY_FLAG_FILTERED标记,如果事件被过滤掉了就直接return了,如果事件没被过滤掉。
6 根据inputreader上来的数据构建触摸事件
7 触摸事件构建成功 唤醒InputDispatcher线程处理事件
1.1 验证是否是有效事件
static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
const PointerProperties* pointerProperties) {
if (!isValidMotionAction(action, actionButton, pointerCount)) {
//验证action是否有效
ALOGE("Motion event has invalid action code 0x%x", action);
return false;
}
if (pointerCount < 1 || pointerCount > MAX_POINTERS) {
//验证触控点数量是否正常
ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %d.",
pointerCount, MAX_POINTERS);
return false;
}
BitSet32 pointerIdBits;
for (size_t i = 0; i < pointerCount; i++) {
int32_t id = pointerProperties[i].id;
if (id < 0 || id > MAX_POINTER_ID) {
//验证Pointer Id是否正常
ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", id,
MAX_POINTER_ID);
return false;
}
if (pointerIdBits.hasBit(id)) {
//验证pointer的id 是否有对应的bit
ALOGE("Motion event has duplicate pointer id %d", id);
return false;
}
pointerIdBits.markBit(id);
}
return true;
}
1 isValidMotionAction 验证事件的action类型是否有效
2 验证触控点数量正常
3 验证触控点id是否正常
1.2 dispatchPolicy进行事件拦截
void NativeInputManager::interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
uint32_t& policyFlags) {
ATRACE_CALL();
// Policy:
// - Ignore untrusted events and pass them along.
// - No special filtering for injected events required at this time.
// - Filter normal events based on screen state.
// - For normal events brighten (but do not wake) the screen if currently dim.
bool interactive = mInteractive.load();
if (interactive) {
//flag定义当一个输入事件携带了 POLICY_FLAG_INTERACTIVE 标志时,
//系统可能会将其视为需要交互式处理的事件,这意味着该事件可能需要立即响应
//事件是否需要立即响应
policyFlags |= POLICY_FLAG_INTERACTIVE;
}
//携带了 POLICY_FLAG_INJECTED 标志时,
//系统会将其视为是由应用程序或者其他实体主动注入(inject)到输入事件流中的事件
if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
if (policyFlags & POLICY_FLAG_INTERACTIVE) {
//当输入事件携带了这个标志时,系统会将其视为需要将事件传递给用户进行处理。
policyFlags |= POLICY_FLAG_PASS_TO_USER;
} else {
JNIEnv* env = jniEnv();
jint wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive,
displayId, when, policyFlags);
if (checkAndClearExceptionFromCallback(env,
"interceptMotionBeforeQueueingNonInteractive")) {
wmActions = 0;
}
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
}
} else {
if (interactive) {
//如果是其他注入的事件(满足可交互) 也可以发给用户
policyFlags |= POLICY_FLAG_PASS_TO_USER;
}
}
}
策略过滤会回调到上层InputManagerService最后通过windowCallBack来考虑
1.3 InputFilter过滤
bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
ATRACE_CALL();
jobject inputEventObj;
JNIEnv* env = jniEnv();
//判断事件类型
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
//转换成key事件
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<const KeyEvent*>(inputEvent));
break;
case AINPUT_EVENT_TYPE_MOTION:
//转换成motion事件
inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
static_cast<const MotionEvent*>(inputEvent));
break;
default:
return true; // dispatch the event normally
}
if (!inputEventObj) {
ALOGE("Failed to obtain input event object for filterInputEvent.");
return true; // dispatch the event normally
}
// The callee is responsible for recycling the event.
//来到java层的InputManagerService
jboolean pass = env->CallBooleanMethod(mServiceObj, gServiceClassInfo.filterInputEvent,
inputEventObj, policyFlags);
if (checkAndClearExceptionFromCallback(env, "filterInputEvent")) {
pass = true;
}
env->DeleteLocalRef(inputEventObj);
return pass;
}
native层根据事件类型将事件对象由c++转换成java给到InputManagerService
final boolean filterInputEvent(InputEvent event, int policyFlags) {
synchronized (mInputFilterLock) {
if (mInputFilter != null) {
try {
mInputFilter.filterInputEvent(event, policyFlags);
} catch (RemoteException e) {
/* ignore */
}
return false;
}
}
event.recycle();
return true;
}
将事件给到InputFilter
final public void filterInputEvent(InputEvent event, int policyFlags) {
mH.obtainMessage(MSG_INPUT_EVENT, policyFlags, 0, event).sendToTarget();
}
通过Handler发送MSG_INPUT_EVENT消息
private final class H extends Handler {
public H(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_INSTALL:
mHost = (IInputFilterHost) msg.obj;
if (mInboundInputEventConsistencyVerifier != null) {
mInboundInputEventConsistencyVerifier.reset();
}
if (mOutboundInputEventConsistencyVerifier != null) {
mOutboundInputEventConsistencyVerifier.reset();
}
onInstalled();
break;
case MSG_UNINSTALL:
try {
onUninstalled();
} finally {
mHost = null;
}
break;
case MSG_INPUT_EVENT: {
final InputEvent event = (InputEvent)msg.obj;
try {
if (mInboundInputEventConsistencyVerifier != null) {
mInboundInputEventConsistencyVerifier.onInputEvent(event, 0);
}
//处理输入事件
onInputEvent(event, msg.arg1);
} finally {
event.recycle();
}
break;
}
}
}
最后由view的InputFilter处理事件
1.4 事件入派发队列
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
//事件加入之前如果之前队列是空的 要唤醒InputDispatcher
bool needWake = mInboundQueue.empty();
//添加队列末尾
mInboundQueue.push_back(entry);
traceInboundQueueLengthLocked();
switch (entry->type) {
case EventEntry::Type::KEY: {
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*entry);
if (isAppSwitchKeyEvent(keyEntry)) {
if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) {
mAppSwitchSawKeyDown = true;
} else if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
if (mAppSwitchSawKeyDown) {
#if DEBUG_APP_SWITCH
ALOGD("App switch is pending!");
#endif
mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT;
mAppSwitchSawKeyDown = false;
needWake = true;
}
}
}
break;
}
case EventEntry::Type::MOTION: {
//检查和修剪输入事件队列中的 Motion 事件
if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(*entry))) {
//mNextUnblockedEvent 保证下次事件可以及时响应
mNextUnblockedEvent = entry;
needWake = true;
}
break;
}
case EventEntry::Type::FOCUS: {
LOG_ALWAYS_FATAL("Focus events should be inserted using enqueueFocusEventLocked");
break;
}
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
// nothing to do
break;
}
}
return needWake;
}
如果添加事件到派发队列时 当前队列如果没有事件那么needWake = true
2 InputDispatcher第二部分
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()) {
//保证命令队列(一次事件处理完整结束)无事件才会执行
dispatchOnceInnerLocked(&nextWakeupTime);
}
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
//根据遍历CommandQueue里的元素执行command函数决定是否立刻唤醒
if (runCommandsLockedInterruptible()) {
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 当前commandQueue无command 或者一次事件完整处理完
执行下一次事件处理
2 考虑遍历commandQueue的元素来决定是否立刻唤醒派发线程
2.1 一次事件处理
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) {
//如果mPendingEvent是null
if (mInboundQueue.empty()) {
//派发队列也是空
if (isAppSwitchDue) {
//存在app切换操作
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
//清除AppSwitch事件应用切换标志为false
//为什么事件队列为空 就不需要在等了呢
//原因 isAppSwitchDue 为 true
//代表下次事件一定是app切换事件 但是事件队列没有
//那么他肯定就不会再来了
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.
//检查缓存事件的flag是否有POLICY_FLAG_PASS_TO_USER flag
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;
//POLICY_FLAG_PASS_TO_USER
//标记表示输入法在处理用户输入时,会充分尊重用户的交互需求,
//让用户能够参与到输入过程并及时调整
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
//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: {
ConfigurationChangedEntry* typedEntry =
static_cast<ConfigurationChangedEntry*>(mPendingEvent);
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
dropReason = DropReason::NOT_DROPPED; // configuration changes are never dropped
break;
}
case EventEntry::Type::DEVICE_RESET: {
DeviceResetEntry* typedEntry = static_cast<DeviceResetEntry*>(mPendingEvent);
done = dispatchDeviceResetLocked(currentTime, typedEntry);
dropReason = DropReason::NOT_DROPPED; // device resets are never dropped
break;
}
case EventEntry::Type::FOCUS: {
FocusEntry* typedEntry = static_cast<FocusEntry*>(mPendingEvent);
dispatchFocusLocked(currentTime, typedEntry);
done = true;
dropReason = DropReason::NOT_DROPPED; // focus events are never dropped
break;
}
case EventEntry::Type::KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
if (isAppSwitchDue) {
if (isAppSwitchKeyEvent(*typedEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DropReason::NOT_DROPPED) {
dropReason = DropReason::APP_SWITCH;
}
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::Type::MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
//因为应用切换丢弃当前事件 并且声明丢弃原因
if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
dropReason = DropReason::APP_SWITCH;
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
dropReason = DropReason::STALE;
}
//如果存在mNextUnblockedEvent事件 需要丢弃当次事件
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
//处理motion事件
done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
}
if (done) {
//如果事件被丢弃
if (dropReason != DropReason::NOT_DROPPED) {
//Log打印事件丢弃原因
dropInboundEventLocked(*mPendingEvent, dropReason);
}
//记录上次丢弃原因
mLastDropReason = dropReason;
//清除当次缓存事件 开启下一次事件循环
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
1 查看派发是否开启
2 查看派发是否被冻结 例如横竖屏转换
3 检查当前是否处于应用切换按键操作
4 获取缓存事件
4.1 事件队列有事件
直接从队列头部取出事件
4.2 事件队列无事件
1 如果当前是应用切换状态 那么可以直接重置应用切换相关缓存
2 如果存在重复事件 则根据上次事件生成当次事件
缓存事件为空 直接返回 等待下一次事件处理
5 检查缓存事件Flag
POLICY_FLAG_PASS_TO_USER
标记表示输入法在处理用户输入时,会充分尊重用户的交互需求,
让用户能够参与到输入过程并及时调整 及时交互反馈
6 根据事件类型 强制转换相关事件
7 根据应用是否切换isAppSwitchDue
是否为stale event
下一次事件是否提前执行mNextUnblockedEvent
来定义当次事件丢弃原因
8 执行dispatchMotionLocked 处理当次motion事件
9 处理完成 根据dropReason 打印相关丢弃事件原因log
对丢弃原因进行记录
释放当次缓存事件
设置下次唤醒时间为LONG_LONG_MIN
2.2 dispatchMotionLocked函数处理
bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, 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) {
//根据DropReason设置注入结果
setInjectionResult(entry,
*dropReason == DropReason::POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
: INPUT_EVENT_INJECTION_FAILED);
return true;
}
//确认当次事件是否为手指事件
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
// Identify targets.
//派发目标集合
std::vector<InputTarget> inputTargets;
bool conflictingPointerActions = false;
int32_t injectionResult;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
//手指事件 根据touch找到合适窗口
injectionResult =
findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
&conflictingPointerActions);
} else {
// Non touch event. (eg. trackball)
//非手指触摸事件 通过窗口焦点找到合适窗口
injectionResult =
findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
}
//注入结果为INPUT_EVENT_INJECTION_PENDING
//退出当次事件派发 等待下一次
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
//设置对应事件的注入结果
setInjectionResult(entry, injectionResult);
if (injectionResult == INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
//如果注入结果为INPUT_EVENT_INJECTION_PERMISSION_DENIED
ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
return true;
}
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
//如果注入的结果不是成功 那么根据是否是手指触摸事件生成cancel事件
//注入到事件队列
CancelationOptions::Mode mode(isPointerEvent
? CancelationOptions::CANCEL_POINTER_EVENTS
: CancelationOptions::CANCEL_NON_POINTER_EVENTS);
CancelationOptions options(mode, "input event injection failed");
synthesizeCancelationEventsForMonitorsLocked(options);
return true;
}
// Add monitor channels from event's or focused display.
//查看当前是否属于touch的down事件
bool isShowTouchDump = false;
if ((entry->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN
|| (entry->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN) {
isShowTouchDump = true;
}
//根据touch事件或者key事件 打印相关log 窗口信息 等等
ALOGD("addGlobalMonitoringTargetsLocked isShowTouchDump: %s", isShowTouchDump ? "true" : "false");
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry), isShowTouchDump, false);
if (isPointerEvent) {
std::unordered_map<int32_t, TouchState>::iterator it =
mTouchStatesByDisplay.find(entry->displayId);
if (it != mTouchStatesByDisplay.end()) {
const TouchState& state = it->second;
if (!state.portalWindows.empty()) {
// The event has gone through these portal windows, so we add monitoring targets of
// the corresponding displays as well.
for (size_t i = 0; i < state.portalWindows.size(); i++) {
const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo();
addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId, false, false,
-windowInfo->frameLeft, -windowInfo->frameTop);
}
}
}
}
// Dispatch the motion.
//如果手指行为action存在冲突 那会生成cancel事件加入事件队列在分发到窗口
if (conflictingPointerActions) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"conflicting pointer actions");
synthesizeCancelationEventsForAllConnectionsLocked(options);
}
//派发事件到指定窗口
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
1 查看当前事件是否处于派发中
2 根据丢弃原因设置注入结果
3 判断当前事件是否为触摸事件
4 查找touch窗口
5 根据查找窗口的结果进行下一步动作
1 INPUT_EVENT_INJECTION_PENDING
当前事件处于缓存状态
退出当前事件,等待下一次派发
2 INPUT_EVENT_INJECTION_PERMISSION_DENIED
当前事件没有权限
退出当次事件
3 != INPUT_EVENT_INJECTION_SUCCEEDED
注入结果失败
根据是否touch事件 生成对应cancel 事件
加入事件队列 等待下一次事件派发循环将事件给到对应窗口
6 根据得到的输入目标窗口 遍历打印相关log
7 如果touch事件存在冲突 和5.3一样
8 将事件注入指定窗口
2.3 输入事件进入派发队列
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
const std::vector<InputTarget>& inputTargets) {
ATRACE_CALL();
#if DEBUG_DISPATCH_CYCLE
ALOGD("dispatchEventToCurrentInputTargets");
#endif
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(*eventEntry);
//遍历touch的窗口
for (const InputTarget& inputTarget : inputTargets) {
//只要通道不为空
sp<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());
}
}
}
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
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=0x%08x, "
"globalScaleFactor=%f, pointerIds=0x%x %s",
connection->getInputChannelName().c_str(), inputTarget.flags,
inputTarget.globalScaleFactor, inputTarget.pointerIds.value,
inputTarget.getPointerInfoString().c_str());
#endif
// 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(), connection->getStatusLabel());
#endif
return;
}
// Split a motion event if needed.
//需要拆分的事件
if (inputTarget.flags & InputTarget::FLAG_SPLIT) {
LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION,
"Entry type %s should not have FLAG_SPLIT",
EventEntry::typeToString(eventEntry->type));
const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
MotionEntry* splitMotionEntry =
splitMotionEvent(originalMotionEntry, inputTarget.pointerIds);
if (!splitMotionEntry) {
return; // split event was dropped
}
if (DEBUG_FOCUS) {
ALOGD("channel '%s' ~ Split motion event.",
connection->getInputChannelName().c_str());
logOutboundMotionDetails(" ", *splitMotionEntry);
}
enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget);
splitMotionEntry->release();
return;
}
}
//不需要拆分的事件
// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
检查输入目标的标志中是否包含InputTarget::FLAG_SPLIT。如果是拆分事件,会对事件类型进行检查,然后对原始的运动事件进行拆分处理,生成新的拆分事件,并将其加入到事件派发队列中。最后释放拆分事件的资源。
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
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());
}
bool wasEmpty = connection->outboundQueue.empty();
// 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.empty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
输入事件进入派发队列
这里涉及请求模式
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT
,表示将事件派发到输入窗口,并将其标记为鼠标悬停退出事件。这通常用于处理鼠标悬停操作。当鼠标从一个窗口的可接收悬停事件的区域移出时,会触发该标志位对应的派发操作,通知窗口处理鼠标悬停退出的逻辑。
InputTarget::FLAG_DISPATCH_AS_OUTSIDE
表示将事件派发到输入窗口,并将其标记为外部触摸事件。这通常用于处理触摸事件在窗口之外的情况。当触摸事件发生在窗口之外时,会触发该标志位对应的派发操作,通知窗口处理外部触摸事件的逻辑
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER
表示将事件派发到输入窗口,并将其标记为鼠标悬停进入事件。这通常用于处理鼠标悬停操作。当可接收悬停事件进入一个窗口时,会触发该标志位对应的派发操作,通知窗口处理鼠标悬停进入的逻辑。
InputTarget::FLAG_DISPATCH_AS_IS
表示将事件派发到输入窗口,并将其标记为普通的输入事件。这通常用于处理普通的输入操作,如键盘输入、鼠标点击等。当普通的输入事件发生时,会触发该标志位对应的派发操作,通知窗口处理普通的输入事件的逻辑。
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT
表示将事件派发到输入窗口,但是不会造成焦点的变化。这通常用于处理“滑动”场景,在滑动过程中,我们需要不断向当前焦点窗口发送滑动事件,但是不能改变窗口的焦点状态
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER
表示将事件派发到输入窗口,并且在派发事件时不会改变窗口的焦点状态。这通常用于处理“滑动”场景,在滑动过程中,我们需要不断向当前焦点窗口发送滑动事件,但是不能改变窗口的焦点状态,直到滑动结束才能改变焦点状态
void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget,
int32_t dispatchMode) {
std::unique_ptr<DispatchEntry> dispatchEntry =
createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);
switch (newEntry->type) {
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 & 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;
dispatchEntry->resolvedEventId = motionEntry.id;
}
}
// Enqueue the dispatch entry.
//通过调用dispatchEntry.release()方法,我们释放了dispatchEntry智能指针的所有权,
//并返回一个指向该对象的裸指针。然后,使用push_back()方法将该裸指针
//添加到connection对象的outboundQueue队列的末尾。
//这样做的目的是将dispatchEntry对象添加到outboundQueue队列中,
//以便后续进行处理或发送给其他组件。注意,由于我们已经释放了dispatchEntry的所有权,
//所以在outboundQueue中存储的是裸指针,而不是智能指针。
//需要确保在适当的时候管理和释放这些指针,以避免内存泄漏。
connection->outboundQueue.push_back(dispatchEntry.release());
}
1 根据InputTarget eventEntry InputTargetFlags 构建dispatchEntry对象
2 根据EventEntry的类型是MOTION 构建motionEntry
来设置dispatchEntry->resolvedAction dispatchEntry->resolvedEventId
3 dispatchEntry对象添加到outboundQueue队列中
2.4 从派发队列派发事件
if (wasEmpty && !connection->outboundQueue.empty()) {
startDispatchCycleLocked(currentTime, connection);
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
const nsecs_t timeout =
getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
dispatchEntry->timeoutTime = currentTime + timeout;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
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 and X and Y scale depending on the input source.
float xOffset = 0.0f, yOffset = 0.0f;
float xScale = 1.0f, yScale = 1.0f;
if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) &&
!(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
float globalScaleFactor = dispatchEntry->globalScaleFactor;
xScale = dispatchEntry->windowXScale;
yScale = dispatchEntry->windowYScale;
xOffset = dispatchEntry->xOffset * xScale;
yOffset = dispatchEntry->yOffset * yScale;
//代表设备无关的坐标转换设备相关的坐标
if (globalScaleFactor != 1.0f) {
//遍历指针数量
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
//将当前motionEntry->pointerCoords[i]赋值到scaledCoords[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, 1 /* windowXScale */,
1 /* windowYScale */);
}
//将scaledCoords给到usingCoords
usingCoords = scaledCoords;
}
} else {
// We don't want the dispatch target to know.
//输入目标需要将坐标归零,清空scaledCoords数组
if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i].clear();
}
//赋值给usingCoords
usingCoords = scaledCoords;
}
}
std::array<uint8_t, 32> hmac = getSignature(*motionEntry, *dispatchEntry);
// Publish the motion event.
//上传该motion事件
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, xScale, yScale,
xOffset, yOffset, motionEntry->xPrecision,
motionEntry->yPrecision,
motionEntry->xCursorPosition,
motionEntry->yCursorPosition,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount,
motionEntry->pointerProperties, usingCoords);
reportTouchEventForStatistics(*motionEntry);
break;
}
}
// 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) {
//如果窗口无响应将派发事件的超时时间和派发窗口token加入到ANR触发器
mAnrTracker.insert(dispatchEntry->timeoutTime,
connection->inputChannel->getConnectionToken());
}
traceWaitQueueLength(connection);
}
}
}
1 确认连接通道正常 且派发队列事件不为空
2 outboundQueue头部取出数据
设置分发时间 当前时间
获取超时时间间隔
设置超时时间
3 根据事件类型MOTION
创建窗口可用指针数组scaledCoords
usingCoords指向motion事件的pointerCoords
4 设置默认x y 偏移 和 x y 缩放
5 判断当前source是POINTER 并且targetFlaget 不是InputTarget::FLAG_ZERO_COORDS标志
6 全局缩放因子globalScaleFactor == 1.0f代表不需要调整设备坐标
7 全局缩放因子globalScaleFactor != 1.0f 需要将当前motionEntry->pointerCoords[i]通过缩放调整为scaledCoords[i]
同时 usingCoords也被赋值为scaledCoords
8 如果targetFlaget 是InputTarget::FLAG_ZERO_COORDS标志
需要将 scaledCoords数组信息清空 赋值给usingCoords
9 通过connection->inputPublisher 将motionEvent发布出去
10 connection->outboundQueue 派发队列删除该事件
11connection->waitQueue 等待队列加入该事件
12 如果窗口无响应将派发事件的超时时间和派发窗口token加入到ANR触发器