文章托管在gitee上 Android Notes , 同步csdn
如前所述,InputDispatcher 是在 InputManager 构造方法中通过工厂方法createInputDispatcher 创建.
此处的policy 实际上就是 NativeInputManager, 它是相关策略的实现类
sp createInputDispatcher(
const sp& policy) {
// 直接通过new创建
return new android::inputdispatcher::InputDispatcher(policy);
}
构造函数主要做一些初始化工作
/// @frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
InputDispatcher::InputDispatcher(const sp& 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);
}
事件派发策略, 它的实现通常是在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,
const sp& token, const std::string& reason) = 0; // 通知ANR
/* Notifies the system that an input channel is unrecoverably broken. */
virtual void notifyInputChannelBroken(const sp& token) = 0;
virtual void notifyFocusChanged(const sp& oldToken, const sp& 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& 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& 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& touchedToken) = 0;
};
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);
}
}
IMS#start方法会调用nativeStart, 之后在native会进一步调用InputDispatcher::start. 在这个方法中,会创建其InputThread任务线程. 如前所述,InputThread构造方法内部会创建一个线程,并启动此线程.
status_t InputDispatcher::start() {
if (mThread) {
return ALREADY_EXISTS;
}
mThread = std::make_unique(
"InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
return OK;
}
注意到创建InputThread时有三个参数,第一个是线程的名称,第二个是线程执行threadLoop时回调的函数,此处写法是C++11的lambda表达式,第三个参数是线程销毁前调用来唤醒线程的回调.
因此当线程运行时会不停的调用dispatchOnce, 来完成分发的操作
dispatchOnce 用于完成事件的派发,逻辑比较简洁:
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);
}
这个函数完成一次事件的派发流程. 通常对于一个事件,调用一次就可以完成派发, 而某些事件比如key事件,当需要传递给user时,会先经过策略类进行处理,从而导致会调用多次.
这个函数的功能相对简单:
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(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(mPendingEvent);
done = dispatchDeviceResetLocked(currentTime, typedEntry);
dropReason = DropReason::NOT_DROPPED; // device resets are never dropped
break;
}
case EventEntry::Type::FOCUS: {
FocusEntry* typedEntry = static_cast(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(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(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
}
}
此函数用于合成一个重重复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事件的派发流程来分析事件派发的过程.
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 = std::make_unique(
&InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
sp 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 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;
}
下面看一些关键的方法的具体实现.
如上分析, 当key事件需要分发到user时,需要先通过策略处理. 将doInterceptKeyBeforeDispatchingLockedInterruptible方法的操作封装成了一个Command,然后投递到command队列.
在dispatchOnceInnerLocked完后,会执行runCommandsLockedInterruptible处理command, 因此会导致该方法被调用. 在执行完策略处理后,事件的interceptKeyResult有三种取值:
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
CommandEntry* commandEntry) {
KeyEntry* entry = commandEntry->keyEntry;
KeyEvent event = createKeyEvent(*entry);
mLock.unlock();
android::base::Timer t;
// InputChannel对应的IBinder token
sp 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判断是否需要继续还是丢弃事件.
再次回到dispatchKeyLocked分发, 当处理完interceptBeforeDispatch的策略后,若事件没有被丢弃,则会尝试寻找focusd window. 逻辑如下:
返回值表示查找的状态:
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry& entry,
std::vector& inputTargets,
nsecs_t* nextWakeupTime) {
std::string reason;
int32_t displayId = getTargetDisplayId(entry);
sp focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId); // 获取焦点窗口 handle
sp 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;
}
检查注入事件的权限,看是否能向当前窗口注入事件:
bool InputDispatcher::checkInjectionPermission(const sp& 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;
}
看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; // 已超时,不需要等待
}
void InputDispatcher::addWindowTargetLocked(const sp& windowHandle,
int32_t targetFlags, BitSet32 pointerIds,
std::vector& inputTargets) {
// 查找 windowHandle 对应的 InputTarget
std::vector::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 = 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::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函数中的等待,处理结果
}
}
将全局监视器也添加到目标窗口. 通过InputManagerService#monitorInput可以注册事件监听器. PointerEventDispatcher的实现是基于此原理实现的.
void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector& inputTargets,
int32_t displayId, float xOffset,
float yOffset) {
std::unordered_map>::const_iterator it =
mGlobalMonitorsByDisplay.find(displayId);
if (it != mGlobalMonitorsByDisplay.end()) {
const std::vector& 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& 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);
}
再次回到dispatchKeyLocked, 当获取到目标窗口后, 就可以调用dispatchEventLocked来将事件派发到窗口.
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
const std::vector& 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 =
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());
}
}
}
}
这个方法开启了事件派发循环. 当将事件派发到目标窗口,在目标窗口处理完毕后, 会发送一个事件处理的反馈到dispatcher, 这才算一个闭环.
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp& 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(*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);
}
将事件添加到派发队列, 然后看是否启动派发循环
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp& 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);
}
}
对于key事件,对应的inputTarget.flags 只包含上面的FLAG_DISPATCH_AS_IS. 上面虽然加了很多dispatchMode, 但是大都被过滤掉了.
void InputDispatcher::enqueueDispatchEntryLocked(const sp& 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 =
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(*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);
}
回到enqueueDispatchEntriesLocked的最后, 假设需要启动派发循环,将调用startDispatchCycleLocked
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp& 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(eventEntry);
std::array 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);
}
}
具体进行事件派发的是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 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.deviceId = deviceId;
msg.body.key.source = source;
msg.body.key.displayId = displayId;
msg.body.key.hmac = std::move(hmac);
msg.body.key.action = action;
msg.body.key.flags = flags;
msg.body.key.keyCode = keyCode;
msg.body.key.scanCode = scanCode;
msg.body.key.metaState = metaState;
msg.body.key.repeatCount = repeatCount;
msg.body.key.downTime = downTime;
msg.body.key.eventTime = eventTime;
return mChannel->sendMessage(&msg); // 通过 InputChannel 发送信息到Client. 返回值表示了发送结果状态
}
下面的返回值状态值 定义在 system/core/libutils/include/utils/Errors.h
status_t InputChannel::sendMessage(const InputMessage* msg) {
const size_t msgLength = msg->size();
InputMessage cleanMsg;
msg->getSanitizedCopy(&cleanMsg);
ssize_t nWrite;
do { // 此处向socket pair的server端写入, client端将会收到数据
nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
if (nWrite < 0) { // 写入失败
int error = errno;
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ error sending message of type %d, %s", mName.c_str(),
msg->header.type, strerror(error));
#endif
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {
return DEAD_OBJECT;
}
return -error;
}
if (size_t(nWrite) != msgLength) { // 写入不完整
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
mName.c_str(), msg->header.type);
#endif
return DEAD_OBJECT;
}
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type);
#endif
return OK; // 0
}
回到InputDispatcher::startDispatchCycleLocked, 在InputPublisher::publishKeyEvent发布事件后,如果成功,则将从派发队列移除已完成的dispatchEntry,并添加dispatchEntry到waitQueue, 等待client发送反馈,如果超时不能得到反馈,将触发ANR. 如果发布事件失败, 那么需要进行处理, 若是真正的阻塞状态,则进行等待就好;若是其他错误,则会调用abortBrokenDispatchCycleLocked处理管道broken.
void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
const sp& connection,
bool notify) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",
connection->getInputChannelName().c_str(), toString(notify));
#endif
// Clear the dispatch queues.
drainDispatchQueue(connection->outboundQueue); // 清空派发队列
traceOutboundQueueLength(connection);
drainDispatchQueue(connection->waitQueue); / /清空等待队列
traceWaitQueueLength(connection);
// The connection appears to be unrecoverably broken.
// Ignore already broken or zombie connections.
if (connection->status == Connection::STATUS_NORMAL) {
connection->status = Connection::STATUS_BROKEN; // 标记connection状态为STATUS_BROKEN
if (notify) { // 通知broken状态
// Notify other system components.
onDispatchCycleBrokenLocked(currentTime, connection);
}
}
}
void InputDispatcher::drainDispatchQueue(std::deque& queue) {
while (!queue.empty()) {
DispatchEntry* dispatchEntry = queue.front();
queue.pop_front();
releaseDispatchEntry(dispatchEntry);
}
}
看onDispatchCycleBrokenLocked实现,实际上就是投递了一个command. 最终的操作会交给doNotifyInputChannelBrokenLockedInterruptible
void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime,
const sp& connection) {
ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
connection->getInputChannelName().c_str());
std::unique_ptr commandEntry = std::make_unique(
&InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
commandEntry->connection = connection;
postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) {
sp connection = commandEntry->connection;
if (connection->status != Connection::STATUS_ZOMBIE) { // 不是 unregistered 状态
mLock.unlock();
// 通知策略类,此connection的InputChannel的broken状态
mPolicy->notifyInputChannelBroken(connection->inputChannel->getConnectionToken());
mLock.lock();
}
}
到此,关于key的派发已经通过InputChannel发送给了client, 后续client处理完后,会发送处理完毕的反馈.
回到InputDispatcher::dispatchOnceInnerLocked,当处理完事件派发后, 会根据dispatchKeyLocked的返回值done判断是否结束此处派发, 如果事件被丢弃了或者派发完成都会返回true
InputDispatcher::dispatchOnceInnerLocked(...){
...
if (done) { // 完成派发?
if (dropReason != DropReason::NOT_DROPPED) { // 如果被丢弃
// 给被丢弃的事件补发一个取消事件 AKEY_EVENT_ACTION_UP
dropInboundEventLocked(*mPendingEvent, dropReason); // 处理丢弃的事件
}
mLastDropReason = dropReason; // 记录此处丢弃原因
releasePendingEventLocked(); // 释放mPendingEvent
// 立减进行下一轮派发
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
接下来看drop事件的处理
void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) {
const char* reason;
switch (dropReason) {
case DropReason::POLICY: // 因为策略被丢弃, 事件可能在策略中被消耗
ALOGD("Dropped event because policy consumed it.");
reason = "inbound event was dropped because the policy consumed it";
break;
case DropReason::DISABLED: // 事件分发被禁止,通常设备处于 non-interactive
if (mLastDropReason != DropReason::DISABLED) {
ALOGI("Dropped event because input dispatch is disabled.");
}
reason = "inbound event was dropped because input dispatch is disabled";
break;
case DropReason::APP_SWITCH: // app切换时间到期,需要丢弃此事件之前的所有事件
ALOGI("Dropped event because of pending overdue app switch.");
reason = "inbound event was dropped because of pending overdue app switch";
break;
case DropReason::BLOCKED: // 用户切换到新应用,因而丢弃之前
ALOGI("Dropped event because the current application is not responding and the user "
"has started interacting with a different application.");
reason = "inbound event was dropped because the current application is not responding "
"and the user has started interacting with a different application";
break;
case DropReason::STALE: // 事件长时间没有被处理,已过期
ALOGI("Dropped event because it is stale.");
reason = "inbound event was dropped because it is stale";
break;
case DropReason::NOT_DROPPED: {
LOG_ALWAYS_FATAL("Should not be dropping a NOT_DROPPED event");
return;
}
}
switch (entry.type) {
case EventEntry::Type::KEY: {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);
// 此处尝试向所有的connection派发取消事件
synthesizeCancelationEventsForAllConnectionsLocked(options);
break;
}
case EventEntry::Type::MOTION: {
const MotionEntry& motionEntry = static_cast(entry);
if (motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason);
synthesizeCancelationEventsForAllConnectionsLocked(options);
} else {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);
synthesizeCancelationEventsForAllConnectionsLocked(options);
}
break;
}
case EventEntry::Type::FOCUS:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("Should not drop %s events", EventEntry::typeToString(entry.type));
break;
}
}
}
void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options) {
for (const auto& pair : mConnectionsByFd) { // 遍历所有的connection进行处理
synthesizeCancelationEventsForConnectionLocked(pair.second, options);
}
}
void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
const sp& connection, const CancelationOptions& options) {
if (connection->status == Connection::STATUS_BROKEN) {
return;
}
nsecs_t currentTime = now();
// 创建取消事件, 它的KeyEntry的action是 AKEY_EVENT_ACTION_UP
std::vector cancelationEvents =
connection->inputState.synthesizeCancelationEvents(currentTime, options);
if (cancelationEvents.empty()) {
return;
}
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
"with reality: %s, mode=%d.",
connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason,
options.mode);
#endif
InputTarget target;
sp windowHandle =
getWindowHandleLocked(connection->inputChannel->getConnectionToken());
if (windowHandle != nullptr) { // 获取InputChannel token对应的window信息
const InputWindowInfo* windowInfo = windowHandle->getInfo();
target.setDefaultPointerInfo(-windowInfo->frameLeft, -windowInfo->frameTop,
windowInfo->windowXScale, windowInfo->windowYScale);
target.globalScaleFactor = windowInfo->globalScaleFactor;
}
target.inputChannel = connection->inputChannel;
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
for (size_t i = 0; i < cancelationEvents.size(); i++) {
EventEntry* cancelationEventEntry = cancelationEvents[i];
switch (cancelationEventEntry->type) {
case EventEntry::Type::KEY: {
logOutboundKeyDetails("cancel - ",
static_cast(*cancelationEventEntry));
break;
}
case EventEntry::Type::MOTION: {
logOutboundMotionDetails("cancel - ",
static_cast(*cancelationEventEntry));
break;
}
case EventEntry::Type::FOCUS: {
LOG_ALWAYS_FATAL("Canceling focus events is not supported");
break;
}
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue",
EventEntry::typeToString(cancelationEventEntry->type));
break;
}
}
// 添加到派发队列
enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
target, InputTarget::FLAG_DISPATCH_AS_IS);
cancelationEventEntry->release();
}
// 开始派发
startDispatchCycleLocked(currentTime, connection);
}
std::vector InputState::synthesizeCancelationEvents(
nsecs_t currentTime, const CancelationOptions& options) {
std::vector events;
// 遍历事件处理记录 , mKeyMementos 在Down事件时通过addKeyMemento添加memento, 在UP事件时删除对应的memento
for (KeyMemento& memento : mKeyMementos) { // 此列表的元素都是已经发生key Down, 但是还没有UP的记录
if (shouldCancelKey(memento, options)) { // 判断是否需要取消key
events.push_back(new KeyEntry(mIdGenerator.nextId(), currentTime, memento.deviceId,
memento.source, memento.displayId, memento.policyFlags,
AKEY_EVENT_ACTION_UP, // up事件
memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode,
memento.scanCode, memento.metaState, 0 /*repeatCount*/,
memento.downTime));
}
}
...// 省略motion event处理
return events;
}
判断是否需要取消key事件, 返回true表示需要.
bool InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) {
if (options.keyCode && memento.keyCode != options.keyCode.value()) { // 判断keyCode
return false;
}
if (options.deviceId && memento.deviceId != options.deviceId.value()) { // 判断deviceId
return false;
}
if (options.displayId && memento.displayId != options.displayId.value()) { // 判断displayId
return false;
}
// 下面根据取消的模式
switch (options.mode) {
case CancelationOptions::CANCEL_ALL_EVENTS:
case CancelationOptions::CANCEL_NON_POINTER_EVENTS: // 上面取消key事件设置的此mode
return true;
case CancelationOptions::CANCEL_FALLBACK_EVENTS:
return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
default:
return false;
}
}
通过对上面的分析来看, 对于被丢弃的事件, 如果之前它存在Down事件, 会尝试补发一个UP事件,补全Down/Up事件对.
到此,dispatchOnceInnerLocked流程大致分析完毕, 回到dispatchOnce, 接下来执行runCommandsLockedInterruptible方法, 来处理pending的commands
这个方法主要用来处理pending的commands, 比如事件分发过程中处理interceptBeforeDispatch, 就是封装成一个command, 在dispatchOnceInnerLocked返回后接着被处理.
bool InputDispatcher::runCommandsLockedInterruptible() {
if (mCommandQueue.empty()) {
return false;
}
do {
std::unique_ptr commandEntry = std::move(mCommandQueue.front()); // 取出头部
mCommandQueue.pop_front();
Command command = commandEntry->command;
// 执行command
command(*this, commandEntry.get()); // commands are implicitly 'LockedInterruptible'
commandEntry->connection.clear();
} while (!mCommandQueue.empty());
return true;
}
在处理完command后, 会处理ANR检查,返回值表示下次唤醒的事件,方法逻辑如下:
/**
* Check if any of the connections' wait queues have events that are too old.
* If we waited for events to be ack'ed for more than the window timeout, raise an ANR.
* Return the time at which we should wake up next.
*/
nsecs_t InputDispatcher::processAnrsLocked() {
const nsecs_t currentTime = now();
nsecs_t nextAnrCheck = LONG_LONG_MAX;
// Check if we are waiting for a focused window to appear. Raise ANR if waited too long
if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {// 等待焦点应用的focused 窗口出现
if (currentTime >= *mNoFocusedWindowTimeoutTime) { // 等待超时
onAnrLocked(mAwaitedFocusedApplication); // 通知ANR
mAwaitedFocusedApplication.clear(); // 清除等待焦点应用信息
return LONG_LONG_MIN;
} else {
// Keep waiting 继续等待焦点窗口出现, 计算到超时事件还有多久
const nsecs_t millisRemaining = ns2ms(*mNoFocusedWindowTimeoutTime - currentTime);
ALOGW("Still no focused window. Will drop the event in %" PRId64 "ms", millisRemaining);
nextAnrCheck = *mNoFocusedWindowTimeoutTime;
}
}
// Check if any connection ANRs are due 检查是否有connection中的ANR触发时间到了
nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout()); // 取出mAnrTracker最近的超时时间
if (currentTime < nextAnrCheck) { // most likely scenario 还没到检查时间,即还没发生ANR
return nextAnrCheck; // everything is normal. Let's check again at nextAnrCheck
}
// If we reached here, we have an unresponsive connection.
sp connection = getConnectionLocked(mAnrTracker.firstToken());
if (connection == nullptr) {
ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout());
return nextAnrCheck;
}
connection->responsive = false; // 修改为未响应
// Stop waking up for this unresponsive connection
mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken()); // 移除此token对应的记录
onAnrLocked(connection); // 通知ANR发生
return LONG_LONG_MIN;
}
void InputDispatcher::onAnrLocked(const sp& connection) {
// Since we are allowing the policy to extend the timeout, maybe the waitQueue
// is already healthy again. Don't raise ANR in this situation
if (connection->waitQueue.empty()) { // 如果此时waitQueue为空,没有等待处理的事件,不触发ANR.此种情况说明connection恢复正常
ALOGI("Not raising ANR because the connection %s has recovered",
connection->inputChannel->getName().c_str());
return;
}
/**
* The "oldestEntry" is the entry that was first sent to the application. That entry, however,
* may not be the one that caused the timeout to occur. One possibility is that window timeout
* has changed. This could cause newer entries to time out before the already dispatched
* entries. In that situation, the newest entries caused ANR. But in all likelihood, the app
* processes the events linearly. So providing information about the oldest entry seems to be
* most useful.
*/
DispatchEntry* oldestEntry = *connection->waitQueue.begin();
const nsecs_t currentWait = now() - oldestEntry->deliveryTime;
std::string reason =
android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
connection->inputChannel->getName().c_str(),
ns2ms(currentWait),
oldestEntry->eventEntry->getDescription().c_str()); // 未响应原因
updateLastAnrStateLocked(getWindowHandleLocked(connection->inputChannel->getConnectionToken()),
reason);
// 将ANR处理的操作封装为command投递到队列. 处理command会调用 doNotifyAnrLockedInterruptible函数
std::unique_ptr commandEntry =
std::make_unique(&InputDispatcher::doNotifyAnrLockedInterruptible);
commandEntry->inputApplicationHandle = nullptr;
commandEntry->inputChannel = connection->inputChannel;
commandEntry->reason = std::move(reason);
postCommandLocked(std::move(commandEntry));
}
看一下updateLastAnrStateLocked方法的处理
void InputDispatcher::updateLastAnrStateLocked(const sp& window,
const std::string& reason) {
const std::string windowLabel = getApplicationWindowLabel(nullptr, window);
updateLastAnrStateLocked(windowLabel, reason);
}
// dump ANR 记录
void InputDispatcher::updateLastAnrStateLocked(const std::string& windowLabel,
const std::string& reason) {
// Capture a record of the InputDispatcher state at the time of the ANR.
time_t t = time(nullptr);
struct tm tm;
localtime_r(&t, &tm);
char timestr[64];
strftime(timestr, sizeof(timestr), "%F %T", &tm);
mLastAnrState.clear();
mLastAnrState += INDENT "ANR:\n";
mLastAnrState += StringPrintf(INDENT2 "Time: %s\n", timestr);
mLastAnrState += StringPrintf(INDENT2 "Reason: %s\n", reason.c_str());
mLastAnrState += StringPrintf(INDENT2 "Window: %s\n", windowLabel.c_str());
dumpDispatchStateLocked(mLastAnrState);
}
处理ANR
void InputDispatcher::doNotifyAnrLockedInterruptible(CommandEntry* commandEntry) {
sp token =
commandEntry->inputChannel ? commandEntry->inputChannel->getConnectionToken() : nullptr;
mLock.unlock();
// 通过策略来通知ANR的发生
const nsecs_t timeoutExtension =
mPolicy->notifyAnr(commandEntry->inputApplicationHandle, token, commandEntry->reason);
mLock.lock();
if (timeoutExtension > 0) { // 延长ANR到timeoutExtension后再触发
extendAnrTimeoutsLocked(commandEntry->inputApplicationHandle, token, timeoutExtension);
} else {
// stop waking up for events in this connection, it is already not responding
sp connection = getConnectionLocked(token);
if (connection == nullptr) {
return;
}
cancelEventsForAnrLocked(connection); // 尝试派发取消事件
}
}
到此InputDispatcher的工作流程分析完毕, 可以发现事件派发的逻辑是串行派发,如果某些事件需要快速响应(如app switch),可能会导致之前的事件被丢弃,而让这些事件得到处理. 下面列出了事件丢弃的原因:
另外,关于两个策略处理函数需要做一些说明:
InputDispatcher的工作主要在dispatchOnce方法中进行处理, 由其工作线程的threadLoop反复调用,处理相关逻辑.
dispatchOnceInnerLocked 进行一次事件派发的逻辑, 流程如下(key事件):
runCommandsLockedInterruptible 执行相关的command,实际上是一系列函数操作的封装. 包括:
processAnrsLocked 处理ANR的相关逻辑
关于重复key事件(repeat key):
本篇主要将了如何将事件从InputDispatcher派发到焦点窗口,但这并不是一个完整的事件派发循环, 当client端处理事件后发送事件反馈, 如何InputDispatcher处理完事件反馈, 这才算是一个完整的事件派发循环. 关于事件反馈的发送与处理将在另一篇详细说明.