Android R input 之 InputDispatcher 工作流程
Posted pecuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android R input 之 InputDispatcher 工作流程相关的知识,希望对你有一定的参考价值。
文章托管在gitee上 Android Notes , 同步csdn
InputDispatcher 的创建
如前所述,InputDispatcher 是在 InputManager 构造方法中通过工厂方法createInputDispatcher 创建.
此处的policy 实际上就是 NativeInputManager, 它是相关策略的实现类
sp<InputDispatcherInterface> createInputDispatcher(
const sp<InputDispatcherPolicyInterface>& policy) {
// 直接通过new创建
return new android::inputdispatcher::InputDispatcher(policy);
}
创建 InputDispatcher
构造函数主要做一些初始化工作
/// @frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
: mPolicy(policy), // 派发策略
mPendingEvent(nullptr), // 待分发的事件
mLastDropReason(DropReason::NOT_DROPPED), // 上次事件丢弃的原因
mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),
mAppSwitchSawKeyDown(false),
mAppSwitchDueTime(LONG_LONG_MAX), // app 切换的超时时间
mNextUnblockedEvent(nullptr),
mDispatchEnabled(false),
mDispatchFrozen(false),
mInputFilterEnabled(false),
// mInTouchMode will be initialized by the WindowManager to the default device config.
// To avoid leaking stack in case that call never comes, and for tests,
// initialize it here anyways.
mInTouchMode(true), // 默认touch mode
// 设置focus DisplayId为默认id
mFocusedDisplayId(ADISPLAY_ID_DEFAULT) {
mLooper = new Looper(false); // 创建 Looper
// The interface used by the InputDispatcher to report information about input events after
// it is sent to the application, such as if a key is unhandled or dropped.
// 上报unhandled or dropped key 的信息, 目前是空实现
mReporter = createInputReporter();
mKeyRepeatState.lastKeyEntry = nullptr;
policy->getDispatcherConfiguration(&mConfig);
}
派发策略 InputDispatcherPolicyInterface
事件派发策略, 它的实现通常是在java层的PhoneWindowManager
class InputDispatcherPolicyInterface : public virtual RefBase {
protected:
InputDispatcherPolicyInterface() {}
virtual ~InputDispatcherPolicyInterface() {}
public:
/* Notifies the system that a configuration change has occurred. */
virtual void notifyConfigurationChanged(nsecs_t when) = 0;
/* Notifies the system that an application is not responding.
* Returns a new timeout to continue waiting, or 0 to abort dispatch. */
virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<IBinder>& token, const std::string& reason) = 0; // 通知ANR
/* Notifies the system that an input channel is unrecoverably broken. */
virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0; // 焦点改变
/* Gets the input dispatcher configuration. */
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
/* Filters an input event.
* Return true to dispatch the event unmodified, false to consume the event.
* A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED
* to injectInputEvent.
*/
virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0;
/* Intercepts a key event immediately before queueing it.
* The policy can use this method as an opportunity to perform power management functions
* and early event preprocessing such as updating policy flags.
*
* This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
* should be dispatched to applications.
*/
virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0; // 入队之前的拦截操作
/* Intercepts a touch, trackball or other motion event before queueing it.
* The policy can use this method as an opportunity to perform power management functions
* and early event preprocessing such as updating policy flags.
*
* This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
* should be dispatched to applications.
*/
virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
uint32_t& policyFlags) = 0;
/* Allows the policy a chance to intercept a key before dispatching. */ // 分发之前的拦截操作
virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,const KeyEvent* keyEvent,uint32_t policyFlags) = 0;
/* Allows the policy a chance to perform default processing for an unhandled key.
* Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */
virtual bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent,uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0;
/* Notifies the policy about switch events.
*/
virtual void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
uint32_t policyFlags) = 0;
/* Poke user activity for an event dispatched to a window. */
virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0;
/* Checks whether a given application pid/uid has permission to inject input events into other applications.
*
* This method is special in that its implementation promises to be non-reentrant and
* is safe to call while holding other locks. (Most other methods make no such guarantees!)
*/
virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
int32_t injectorUid) = 0;
/* Notifies the policy that a pointer down event has occurred outside the current focused window.
*
* The touchedToken passed as an argument is the window that received the input event.
*/
virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0;
};
NativeInputManager::getDispatcherConfiguration
InputDispatcher构造的最后,通过policy获取配置信息, 此处的policy实际上是NativeInputManager对象. 通过实现可知,是通过IMS的相关方法获取时间.
void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
jint keyRepeatTimeout = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getKeyRepeatTimeout); // 通过IMS 获取第一个按键重复事件的超时时间 默认500ms
if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) {
outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout);
}
jint keyRepeatDelay = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getKeyRepeatDelay); // 获取连续重复按键之间的时间 50s
if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay);
}
}
InputDispatcher::start
IMS#start方法会调用nativeStart, 之后在native会进一步调用InputDispatcher::start. 在这个方法中,会创建其InputThread任务线程. 如前所述,InputThread构造方法内部会创建一个线程,并启动此线程.
status_t InputDispatcher::start() {
if (mThread) {
return ALREADY_EXISTS;
}
mThread = std::make_unique<InputThread>(
"InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
return OK;
}
注意到创建InputThread时有三个参数,第一个是线程的名称,第二个是线程执行threadLoop时回调的函数,此处写法是C++11的lambda表达式,第三个参数是线程销毁前调用来唤醒线程的回调.
因此当线程运行时会不停的调用dispatchOnce, 来完成分发的操作
InputDispatcher::dispatchOnce
dispatchOnce 用于完成事件的派发,逻辑比较简洁:
- 没有待处理的commands时, 执行派发操作, 派发是串行的处理
- 处理 pending commands. Command通常是对dispatcher函数相关操作的封装,添加到mCommandQueue,等待dispatcher处理
- 处理 ANR 事件
- 计算下一次的唤醒时间, 若为LONG_LONG_MAX,则通知进入idle
- 通过mLooper->pollOnce等待相关事件, 如 callback / timeout / wake
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
std::scoped_lock _l(mLock);
mDispatcherIsAlive.notify_all(); // 通知dispatcher线程还活跃, 用于检测死锁
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
if (!haveCommandsLocked()) { // 如果没有commands 则进行事件分发
dispatchOnceInnerLocked(&nextWakeupTime);
}
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) { // 执行commands
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(); // 处理anr
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(); // 通知进入idle
}
} // 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);
}
InputDispatcher::dispatchOnceInnerLocked
这个函数完成一次事件的派发流程. 通常对于一个事件,调用一次就可以完成派发, 而某些事件比如key事件,当需要传递给user时,会先经过策略类进行处理,从而导致会调用多次.
这个函数的功能相对简单:
- 取出pending事件, 当队列有事件时取出队列头, 当事件队列为空时,则尝试处理重复事件
- 处理需要 drop 的事件
- 针对type处理相关事件的派发
- 结束事件派发
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) { // 分发被禁止, 通常设备处于 non-interactive
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; // app 切换时间到期
if (mAppSwitchDueTime < *nextWakeupTime) { // 下次唤醒时间大于 app 切换时间到期时间,则更新唤醒时间为早的
*nextWakeupTime = mAppSwitchDueTime;
}
/// 下面进入派发流程
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (!mPendingEvent) { // 尝试获取新的Event来处理
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.
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) { // 下次repeat时间较短,设置成wakeup时间
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// Nothing to do if there is no pending event.
if (!mPendingEvent) { // 没有pending的直接返回
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) { // 传给user, 则需要通知user活动
// 此处会回调到PowerManagerService的userActivityFromNative
// 下面调用会被封装成一个command,在下次派发循环中处理
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;
// 如果不传递给user, 通常是在interceptKeyBeforeQueueing处理是否传递
// 没有FLAG POLICY_FLAG_PASS_TO_USER , 则会因为DropReason::POLICY 而被丢弃
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: { // input device configuration has 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: { // 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: { // 派发 key 事件
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
if (isAppSwitchDue) { // app切换的key事件到期, 需要丢弃此事件之前的所有事件
if (isAppSwitchKeyEvent(*typedEntry)) { // 当前事件是app切换的key事件,则重置到期时间
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DropReason::NOT_DROPPED) { // 否则此未丢弃的事件会因为APP_SWITCH而丢弃
dropReason = DropReason::APP_SWITCH;
}
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) { // 过期事件, 此时距离事件发生时间>=10sec
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) { // 有非阻塞事件需要处理
dropReason = DropReason::BLOCKED;
}
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); // 处理key事件派发
break;
}
case EventEntry::Type::MOTION: { // 派发触摸事件
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) { // app切换到期
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 = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
}
if (done) { // 完成派发?
if (dropReason != DropReason::NOT_DROPPED) { // 如果被丢弃
dropInboundEventLocked(*mPendingEvent, dropReason);
}
mLastDropReason = dropReason;
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
InputDispatcher::synthesizeKeyRepeatLocked
此函数用于合成一个重重复key事件, 注意repeatCount都递增了1
KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) {
KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
// Reuse the repeated key entry if it is otherwise unreferenced.
uint32_t policyFlags = entry->policyFlags &
(POLICY_FLAG_RAW_MASK | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED); // 添加flag
if (entry->refCount == 1) { // 没有其他引用时复用,防止冲突. entry->refCount默认是1
entry->recycle();
entry->id = mIdGenerator.nextId();
entry->eventTime = currentTime;
entry->policyFlags = policyFlags;
entry->repeatCount += 1;
} else { // 已在其他地方被引用,需要创建新entry
KeyEntry* newEntry =
new KeyEntry(mIdGenerator.nextId(), currentTime, entry->deviceId, entry->source,
entry->displayId, policyFlags, entry->action, entry->flags,
entry->keyCode, entry->scanCode, entry->metaState,
entry->repeatCount + 1, entry->downTime);
mKeyRepeatState.lastKeyEntry = newEntry;
entry->release();
entry = newEntry;
}
entry->syntheticRepeat = true; // 设置事件是合成的
// Increment reference count since we keep a reference to the event in
// mKeyRepeatState.lastKeyEntry in addition to the one we return.
entry->refCount += 1;
mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay; // 注意此处的nextRepeatTime,与当前间隔keyRepeatDelay 50ms
return entry;
}
接下来以key事件的派发流程来分析事件派发的过程.
InputDispatcher::dispatchKeyLocked
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
if (!entry->dispatchInProgress) { // 如果不是在派发过程中
// 处理key事件的repeat
// repeat条件: ①repeatCount为0 , ②是Down事件, ③是trusted事件 ④策略没有禁止repeat
// 上面条件说明这是一个 initial Down事件(可能是设备驱动生成的repeat事件)
if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN &&
(entry->policyFlags & POLICY_FLAG_TRUSTED) &&
(!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) {
// 根据下面的注释看,是设备驱动生成了repeat事件, 为什么此处不是之前合成的重复事件? 之前一直忽略了repeatCount成员
// 如果是之前合成的重复事件,repeatCount则不为0(synthesizeKeyRepeatLocked函数对其进行过递增), 上面的repeat条件将不满足而无法进入
if (mKeyRepeatState.lastKeyEntry && // 既然设备驱动生成了repeat事件(也就是当前entry), 那么就不需要自己去合成一个了
mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {// 存在lastKeyEntry, 且keyCode一致 说明此key之前触发过
// We have seen two identical key downs in a row which indicates that the device
// driver is automatically generating key repeats itself. We take note of the
// repeat here, but we disable our own next key repeat timer since it is clear that
// we will not need to synthesize key repeats ourselves.
entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1; // 递增repeatCount
resetKeyRepeatLocked(); // 重置 mKeyRepeatState 为nullptr
mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves
} else {
// Not a repeat. Save key down state in case we do see a repeat later.
resetKeyRepeatLocked();
mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout;
}
mKeyRepeatState.lastKeyEntry = entry; // 设置新的lastKeyEntry
entry->refCount += 1;
} else if (!entry->syntheticRepeat) { // 不是合成的repeat事件
resetKeyRepeatLocked(); // 重置 lastKeyEntry
}
if (entry->repeatCount == 1) { // repeatCount 为1, 则添加长按事件的FLAG
entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
} else {
entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS;
}
entry->dispatchInProgress = true; // 派发中..
logOutboundKeyDetails("dispatchKey - ", *entry);
}
// Handle case where the policy asked us to try again later last time.
// 之前策略决定稍后重试,这个根据PhoneWindowManager#interceptKeyBeforeDispatching 返回值决定
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
if (currentTime < entry->interceptKeyWakeupTime) { // 还未到时间继续 只更新唤醒时间
if (entry->interceptKeyWakeupTime < *nextWakeupTime) {
*nextWakeupTime = entry->interceptKeyWakeupTime;
}
return false; // wait until next wakeup
}
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; // 重置, 让policy再次处理
entry->interceptKeyWakeupTime = 0;
}
// Give the policy a chance to intercept the key.
// interceptKeyResult有三种情况 :
// INTERCEPT_KEY_RESULT_SKIP(跳过派发) INTERCEPT_KEY_RESULT_CONTINUE(继续派发) INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER(稍后重试派发)
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { // 为unknown,认为没有处理过
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { // 如果需要传递给user, 则需要调用策略类进行处理
// 将doInterceptKeyBeforeDispatchingLockedInterruptible操作封装成command,在执行dispatchOnceInnerLocked后处理command
std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
&InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(*entry));// 获取指定displayId对应的focusedWindowHandle
if (focusedWindowHandle != nullptr) {
commandEntry->inputChannel = getInputChannelLocked(focusedWindowHandle->getToken());
}
commandEntry->keyEntry = entry;
postCommandLocked(std::move(commandEntry)); // 投递command
entry->refCount += 1;
return false; // wait for the command to run 此处返回false会先执行command, 然后再继续进行此事件派发
} else { // 否则继续派发
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
}
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) { // 如果是skip则drop事件
if (*dropReason == DropReason::NOT_DROPPED) {
*dropReason = DropReason::POLICY;
}
}
// Clean up if dropping the event.
if (*dropReason != DropReason::NOT_DROPPED) { // 事件丢弃处理
setInjectionResult(entry,
*dropReason == DropReason::POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
: INPUT_EVENT_INJECTION_FAILED); // 设置事件注入的结果
mReporter->reportDroppedKey(entry->id);
return true;
}
// Identify targets.
std::vector<InputTarget> inputTargets; // 目标窗口结果保存在此集合
int32_t injectionResult =
findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime); // 寻找到焦点窗口
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { // pending表示需要等待
return false;
}
setInjectionResult(entry, injectionResult); // 设置事件注入的结果
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { // 非success将不会被派发
return true;
}
// Add monitor channels from event's or focused display.
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry)); // 将monitor列表的window也加入派发目标窗口列表
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets); // 开始派发事件到目标窗口
return true;
}
下面看一些关键的方法的具体实现.
InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible
如上分析, 当key事件需要分发到user时,需要先通过策略处理. 将doInterceptKeyBeforeDispatchingLockedInterruptible方法的操作封装成了一个Command,然后投递到command队列.
在dispatchOnceInnerLocked完后,会执行runCommandsLockedInterruptible处理command, 因此会导致该方法被调用. 在执行完策略处理后,事件的interceptKeyResult有三种取值:
- KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
- KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
- KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
CommandEntry* commandEntry) {
KeyEntry* entry = commandEntry->keyEntry;
KeyEvent event = createKeyEvent(*entry);
mLock.unlock();
android::base::Timer t;
// InputChannel对应的IBinder token
sp<IBinder> token = commandEntry->inputChannel != nullptr
? commandEntry->inputChannel->getConnectionToken()
: nullptr;
// 调用路径 NativeInputManager -> InputManagerService -> InputManagerCallback -> PhoneWindowManager
nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry->policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",
std::to_string(t.duration().count()).c_str());
}
mLock.lock();
if (delay < 0) { // <0 , 事件将会跳过, 可能已经被policy处理了
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
} else if (!delay) { // = 0 , 继续分发
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
} else { // > 0 , 延时分发
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
entry->interceptKeyWakeupTime = now() + delay;
}
entry->release();
}
在处理此command后,会继续进行之前未派发完的事件派发任务, 然后根据interceptKeyResult判断是否需要继续还是丢弃事件.
InputDispatcher::findFocusedWindowTargetsLocked
再次回到dispatchKeyLocked分发, 当处理完interceptBeforeDispatch的策略后,若事件没有被丢弃,则会尝试寻找focusd window. 逻辑如下:
- 获取指定displayId的焦点窗口和焦点应用,如果两者都不存在,则说明没有找到.如果有焦点应用,但是没有焦点窗口,则需要等待焦点窗口的出现, 默认等待5s
- 如果找到焦点窗口,重置ANR相关信息
- 如果是注入(inject)的事件,需要检查相关权限(android.permission.INJECT_EVENTS)
- 如果焦点窗口处于paused状态,则需要等待
- 如果是key事件, 则需要等待之前的事件全部处理完成才派发. 等待超时时间500ms
- 添加当前目标窗口到inputTargets列表, 注意添加时的FLAG FLAG_FOREGROUND和FLAG_DISPATCH_AS_IS
返回值表示查找的状态:
- INPUT_EVENT_INJECTION_FAILED 没有找到焦点窗口或等待焦点窗口出现超时
- INPUT_EVENT_INJECTION_PENDING
- 等待焦点窗口
- 焦点窗口处于paused状态
- 如果是key事件,等待之前的事件全部处理完成 - INPUT_EVENT_INJECTION_PERMISSION_DENIED
- 注册事件的应用uid 与目标窗口应用的uid不一致, 且没有权限 android.permission.INJECT_EVENTS - INPUT_EVENT_INJECTION_SUCCEEDED 找到焦点窗口
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry& entry,
std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime) {
std::string reason;
int32_t displayId = getTargetDisplayId(entry);
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId); // 获取焦点窗口 handle
sp<InputApplicationHandle> focusedApplicationHandle =
getValueByKey(mFocusedApplicationHandlesByDisplay, displayId); // 获取焦点应用handle
// 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 ".",
EventEntry::typeToString(entry.type), displayId);
return INPUT_EVENT_INJECTION_FAILED;
}
// Compatibility behavior: raise ANR if there is a focused application, but no focused window.
// Only start counting when we have a focused event to dispatch. The ANR is canceled if we
// start interacting with another application via touch (app switch). This code can be removed
// if the "no focused window ANR" is moved to the policy. Input doesn't know whether
// an app is expected to have a focused window.
if (focusedWindowHandle == nullptr && focusedApplicationHandle != nullptr) { // 有焦点应用但是没有焦点窗口
if (!mNoFocusedWindowTimeoutTime.has_value()) { // 新窗口可能在添加中, 等待添加完成
// We just discovered that there's no focused window. Start the ANR timer
const nsecs_t timeout = focusedApplicationHandle->getDispatchingTimeout(
DEFAULT_INPUT_DISPATCHING_TIMEOUT.count());
mNoFocusedWindowTimeoutTime = currentTime + timeout;
mAwaitedFocusedApplication = focusedApplicationHandle;
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(), ns2ms(timeout));
*nextWakeupTime = *mNoFocusedWindowTimeoutTime;
return INPUT_EVENT_INJECTION_PENDING; // 返回 pending
} else if (currentTime > *mNoFocusedWindowTimeoutTime) {
// Already raised ANR. Drop the event
ALOGE("Dropping %s event because there is no focused window",
EventEntry::typeToString(entry.type));
return INPUT_EVENT_INJECTION_FAILED; // 已经等待超时, 返回失败
} else {
// Still waiting for the focused window
return INPUT_EVENT_INJECTION_PENDING; // 还未超时, 继续等待
}
}
// we have a valid, non-null focused window
resetNoFocusedWindowTimeoutLocked(); // 重置超时时间, Resetting ANR timeouts
// Check permissions. 主要是通过IMS来检查权限 android.Manifest.permission.INJECT_EVENTS
if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {
return INPUT_EVENT_INJECTION_PERMISSION_DENIED;
}
if (focusedWindowHandle->getInfo()->paused) { // 窗口paused状态,等待
ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str());
return INPUT_EVENT_INJECTION_PENDING;
}
// If the event is a key event, then we must wait for all previous events to
// complete before delivering it because previous events may have the
// side-effect of transferring focus to a different window and we want to
// ensure that the following keys are sent to the new window.
//
// Suppose the user touches a button in a window then immediately presses "A".
// If the button causes a pop-up window to appear then we want to ensure that
// the "A" key is delivered to the new pop-up window. This is because users
// often anticipate pending UI changes when typing on a keyboard.
// To obtain this behavior, we must serialize key events with respect to all
// prior input events.
if (entry.type == EventEntry::Type::KEY) { // 如果是key事件, 则需要等待之前的事件全部处理完成才派发
if (shouldWaitToSendKeyLocked(currentTime, focusedWindowHandle->getName().c_str())) {
*nextWakeupTime = *mKeyIsWaitingForEventsTimeout; // 设置下次唤醒时间为等待超时时间
return INPUT_EVENT_INJECTION_PENDING;
}
}
// Success! Output targets.
addWindowTargetLocked(focusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,// 注意此处的FLAG, 在派发时生成对应的dispatchEntry
BitSet32(0), inputTargets); // 保存到inputTargets
// Done.
return INPUT_EVENT_INJECTION_SUCCEEDED;
}
InputDispatcher::checkInjectionPermission
检查注入事件的权限,看是否能向当前窗口注入事件:
- 注册事件的应用uid 与目标窗口应用的uid一致, 则可以直接注入
- 若不一致, 则还需要权限 android.permission.INJECT_EVENTS
bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
const InjectionState* injectionState) {
if (injectionState &&
(windowHandle == nullptr ||
// 注册事件的应用uid 与目标窗口应用的uid不一致. 此处若相等,则整个if不成立
windowHandle->getInfo()->ownerUid != injectionState->injectorUid) &&
// 没有权限 android.permission.INJECT_EVENTS
!hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
if (windowHandle != nullptr) {
ALOGW("Permission denied: injecting event from pid %d uid %d to window %s "
"owned by uid %d",
injectionState->injectorPid, injectionState->injectorUid,
windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid);
} else {
ALOGW("Permission denied: injecting event from pid %d uid %d",
injectionState->injectorPid, injectionState->injectorUid);
}
return false;
}
return true;
}
InputDispatcher::shouldWaitToSendKeyLocked
看key事件是否需要等待之前的事件派发完成
bool InputDispatcher::shouldWaitToSendKeyLocked(nsecs_t currentTime,
const char* focusedWindowName) {
// mAnrTracker为空,说明之前的事件都已经发送事件反馈,将相关anr记录从其中移除,即事件都已经派发完毕
if (mAnrTracker.empty()) {
// already processed all events that we waited for
mKeyIsWaitingForEventsTimeout = std::nullopt; // 清除等待超时
return false;
}
// 到此说明之前还有事件没有派发完, mKeyIsWaitingForEventsTimeout没有value则说明还没设置等待
if (!mKeyIsWaitingForEventsTimeout.has_value()) {
// Start the timer
ALOGD("Waiting to send key to %s because there are unprocessed events that may cause "
"focus to change",
focusedWindowName);
mKeyIsWaitingForEventsTimeout = currentTime + KEY_WAITING_FOR_EVENTS_TIMEOUT.count(); // 设置等待超时
return true;
}
// We still have pending events, and already started the timer
if (currentTime < *mKeyIsWaitingForEventsTimeout) { // 判断等待超时事件是否还没有到
return true; // Still waiting
}
// Waited too long, and some connection still hasn't processed all motions
// Just send the key to the focused window
ALOGW("Dispatching key to %s even though there are other unprocessed events",
focusedWindowName);
mKeyIsWaitingForEventsTimeout = std::nullopt; // 清除等待超时
return false; // 已超时,不需要等待
}
InputDispatcher::addWindowTargetLocked
void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds,
std::vector<InputTarget>& inputTargets) {
// 查找 windowHandle 对应的 InputTarget
std::vector<InputTarget>::iterator it =
std::find_if(inputTargets.begin(), inputTargets.end(),
[&windowHandle](const InputTarget& inputTarget) {
return inputTarget.inputChannel->getConnectionToken() ==
windowHandle->getToken(); // 根据InputChannel的token判断是否存在
});
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (it == inputTargets.end()) { // 不存在对应的InputTarget
InputTarget inputTarget;
sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken()); // 根据token查找InputChannel
if (inputChannel == nullptr) { // 不存在InputChannel, 直接返回
ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
return;
}
// 初始化 InputTarget
inputTarget.inputChannel = inputChannel;
inputTarget.flags = targetFlags;
inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; // ignored for KeyEvents
inputTargets.push_back(inputTarget);
it = inputTargets.end() - 1;
}
ALOG_ASSERT(it->flags == targetFlags);
ALOG_ASSERT(it->globalScaleFactor == windowInfo->globalScaleFactor);
it->addPointers(pointerIds, -windowInfo->frameLeft, -windowInfo->frameTop,
windowInfo->windowXScale, windowInfo->windowYScale); // 设置Pointer信息
}
InputDispatcher::setInjectionResult
这个函数用于设置通过InputDispatcher::injectInputEvent 注入事件的结果. 后续再开篇分析事件注入.
void InputDispatcher::setInjectionResult(EventEntry* entry, int32_t injectionResult) {
InjectionState* injectionState = entry->injectionState;
if (injectionState) { // 不为nullptr, 则是通过injectInputEvent注入的事件
#if DEBUG_INJECTION
ALOGD("Setting input event injection result to %d. "
"injectorPid=%d, injectorUid=%d",
injectionResult, injectionState->injectorPid, injectionState->injectorUid);
#endif
if (injectionState->injectionIsAsync && !(entry->policyFlags & POLICY_FLAG_FILTERED)) {
// Log the outcome since the injector did not wait for the injection result.
switch (injectionResult) {
case INPUT_EVENT_INJECTION_SUCCEEDED:
ALOGV("Asynchronous input event injection succeeded.");
break;
case INPUT_EVENT_INJECTION_FAILED:
ALOGW("Asynchronous input event injection failed.");
break;
case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
ALOGW("Asynchronous input event injection permission denied.");
break;
case INPUT_EVENT_INJECTION_TIMED_OUT:
ALOGW("Asynchronous input event injection timed out.");
break;
}
}
injectionState->injectionResult = injectionResult;
mInjectionResultAvailable.notify_all(); // 唤醒在injectInputEvent函数中的等待,处理结果
}
}
InputDispatcher::addGlobalMonitoringTargetsLocked
将全局监视器也添加到目标窗口. 通过InputManagerService#monitorInput可以注册事件监听器. PointerEventDispatcher的实现是基于此原理实现的.
void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets,
int32_t displayId, float xOffset,
float yOffset) {
std::unordered_map<int32_t, std::vector<Monitor>>::const_iterator it =
mGlobalMonitorsByDisplay.find(displayId);
if (it != mGlobalMonitorsByDisplay.end()) {
const std::vector<Monitor>& monitors = it->second;
for (const Monitor& monitor : monitors) {
addMonitoringTargetLocked(monitor, xOffset, yOffset, inputTargets);
}
}
}
addMonitoringTargetLocked方法如下
void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xOffset,
float yOffset,
std::vector<InputTarget>& inputTargets) {
InputTarget target;
target.inputChannel = monitor.inputChannel;
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
target.setDefaultPointerInfo(xOffset, yOffset, 1 /* windowXScale */, 1 /* windowYScale */);
inputTargets.push_back(target);
}
InputDispatcher::dispatchEventLocked
再次回到dispatchKeyLocked, 当获取到目标窗口后, 就可以调用dispatchEventLocked来将事件派发到窗口.
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); // 通知PMS user activity
for (const InputTarget& inputTarget : inputTargets) { // 遍历目标窗口
sp<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken()); // 根据InputChannel的token获取窗口的connection
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());
}
}
}
}
InputDispatcher::prepareDispatchCycleLocked
这个方法开启了事件派发循环. 当将事件派发到目标窗口,在目标窗口处理完毕后, 会发送一个事件处理的反馈到dispatcher, 这才算一个闭环.
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget) {
if (ATRACE_ENABLED()) { /// trace
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) { // connection状态不是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);
}
InputDispatcher::enqueueDispatchEntriesLocked
将事件添加到派发队列, 然后看是否启动派发循环
- 原来有事件在处理, 需要等待之前的结束
- 原来队列是空, 则需要启动派发循环
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();
// 添加dispatchEntry, 根据inputTarget的flags过滤不必要的, 对于key事件,对应的FLAG是FLAG_DISPATCH_AS_IS
// 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); // key事件这个dispatchMode会添加
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// connection的派发队列为空, 添加新元素,会启动connection的事件派发, 否则等待之前的事件派发完成
// 即之前的事件派发循环的反馈收到后, 再继续下一个派发循环
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.empty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
InputDispatcher::enqueueDispatchEntryLocked
对于key事件,对应的inputTarget.flags 只包含上面的FLAG_DISPATCH_AS_IS. 上面虽然加了很多dispatchMode, 但是大都被过滤掉了.
void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget,
int32_t dispatchMode) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf("enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)",
connection->getInputChannelName().c_str(),
dispatchModeToString(dispatchMode).c_str());
ATRACE_NAME(message.c_str());
}
int32_t inputTargetFlags = inputTarget.flags;
if (!(inputTargetFlags & dispatchMode)) { // 过滤掉不包含的dispatchMode
return;
}
// 去掉除了dispatchMode的其他mode
inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | 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); // 对要派发的事件创建一个 DispatchEntry
// 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)) { // 处理 inconsistent key event
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
connection->getInputChannelName().c_str());
#endif
return; // skip the inconsistent event
}
break;
}
case EventEntry::Type::MOTION: {...
case EventEntry::Type::FOCUS: {...
case EventEntry::Type::CONFIGURATION_CHANGED: ...
case EventEntry::Type::DEVICE_RESET: {...
}
// Remember that we are waiting for this dispatch to complete.
if (dispatchEntry->hasForegroundTarget()) { // 实际上就是判断 targetFlags & InputTarget::FLAG_FOREGROUND , 处理key事件添加了此FLAG
incrementPendingForegroundDispatches(newEntry); // 尝试增加 injectionState->pendingForegroundDispatches
}
// Enqueue the dispatch entry.
connection->outboundQueue.push_back(dispatchEntry.release()); // 添加到connection->outboundQueue
traceOutboundQueueLength(connection);
}
InputDispatcher::startDispatchCycleLocked
回到enqueueDispatchEntriesLocked的最后, 假设需要启动派发循环,将调用startDispatchCycleLocked
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 = // 计算超时时间,优先取出window->getDispatchingTimeout, 默认5s
getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
dispatchEntry->timeoutTime = currentTime + timeout;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::Type::KEY: {
const KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
std::array<uint8_t, 32> hmac = getSignature(*keyEntry, *dispatchEntry);
// Publish the key event.
status = /// 派发key事件
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: {...
case EventEntry::Type::FOCUS: {...
case EventEntry::Type::CONFIGURATION_CHANGED:...
case EventEntry::Type::DEVICE_RESET: {...
}
// Check the result.
if (status) { /// 不为 0 = OK , 说明派发失败
if (status == WOULD_BLOCK) {
if (connection->waitQueue.empty()) { // waitQueue 为空,没有需要等待反馈的事件,理论上发送不应该是阻塞的,说明出了问题
ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
"This is unexpected because the wait queue is empty, so the pipe "
"should be empty and we shouldn't have any problems writing an "
"event to it, status=%d",
connection->getInputChannelName().c_str(), status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);// 处理 broken状态
} else { // 这种情况需等待client处理完之前的事件
// 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());
#endif
}
} else { // 其他错误
ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
"status=%d",
connection->getInputChannelName().c_str(), status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);// 处理 broken状态
}
return; // 发送失败,此处直接返回
}
// Re-enqueue the event on the wait queue.
connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
connection->outboundQueue.end(),
dispatchEntry)); // 从派发队列移除已完成的dispatchEntry
traceOutboundQueueLength(connection);
connection->waitQueue.push_back(dispatchEntry); // 添加dispatchEntry到waitQueue, 等待client发送反馈
if (connection->responsive) { // 如果connection处理可响应状态, 添加anr追踪
mAnrTracker.insert(dispatchEntry->timeoutTime, // 超时时间
connection->inputChannel->getConnectionToken()); // InputChannel的token
}
traceWaitQueueLength(connection);
}
}
InputPublisher.publishKeyEvent
具体进行事件派发的是Connection的成员InputPublisher
/// @frameworks/native/libs/input/InputTransport.cpp
status_t InputPublisher::publishKeyEvent(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 flags, int32_t keyCode, int32_t scanCode,
int32_t metaState, int32_t repeatCount, nsecs_t downTime,
nsecs_t eventTime) {
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
"action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
"downTime=%" PRId64 ", eventTime=%" PRId64,
mChannel->getName().c_str(), seq, deviceId, source, action, flags, keyCode, scanCode,
metaState, repeatCount, downTime, eventTime);
}
if (!seq) {
ALOGE("Attempted to publish a key event with sequence number 0.");
return BAD_VALUE;
}
// 将相关信息转换为 InputMessage
InputMessage msg;
msg.header.type = InputMessage::Type::KEY;
msg.body.key.seq = seq;
msg.body.key.eventId = eventId;
msg.body.key.devi以上是关于Android R input 之 InputDispatcher 工作流程的主要内容,如果未能解决你的问题,请参考以下文章
Android R input 之 InputChannel之发送事件处理反馈
Android R input 之 InputDispatcher 工作流程
Android R input 之 InputDispatcher 工作流程
Android R input 之 InputManagerService 的建立