InputManagerService分发输入事件给应用程序(下)
2017-09-30 19:43
429 查看
InputManagerService分发输入事件给应用程序(下)
InputManagerService分发输入事件给应用程序下简介
源码分析
总结
1.简介
在InputManagerService分发输入事件消息给应用程序(上)中介绍了InputReader从EventHub中获取输入事件,并对输入事件进行加工处理,然后将输入事件放入到InputDispatcher的mInboundQueue队列,并通过Looper->wake()方法唤醒InputDispatcherThread线程。本篇文章将从InputDispatcherThread线程开始分析,InputDispatcher如何将输入事件分发到应用程序激活的Activity窗口。2.源码分析
在InputDispatcherThread线程中,会循环调用其threadLoop()方法。2.1 InputDispatcherThread.threadLoop()
bool InputDispatcherThread::threadLoop() { mDispatcher->dispatchOnce(); return true; }
当threadLoop()方法返回true时,代表将循环调用loopOnce()方法。当threadLoop()方法返回false时,代表退出循环。
void InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock AutoMutex _l(mLock); mDispatcherIsAliveCondition.broadcast(); if (!haveCommandsLocked()) {//当mCommandQueue队列为空时,则说明当前没有等待执行任务,则可以进行分发任务。 dispatchOnceInnerLocked(&nextWakeupTime);//分发输入事件,见2.2 } if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; } } // 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);//进入epoll_wait等待状态 }
在调用InputDispatcher的dispatchOnce()方法时,如果没有输入事件需要分发,则会调用Looper的pollOnce()方法,进入epoll_wait等待状态。
当发送以下3种情况时,会退出epoll_wait等待状态:
callback:通过回调方法唤醒;
timeout:超时时间timeoutMillis唤醒;
wake:主动通过Looper->wake()方法唤醒;
当InputDispatcher退出epoll_wait等待状态,会返回到dispatchOnce()方法,再返回到threadLoop()方法,因为返回值为true,所以接着又循环调用threadLoop()方法,重新进入dispatchOnce()方法。因为此时已经有输入事件需要处理了,所以会调用dispatchOnceInnerLocked()方法进行处理。
2.2 InputDispatcher.dispatchOnceInnerLocked()
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { nsecs_t currentTime = now();//获取当前时间 //分发禁用了,则重置key重复操作; if (!mDispatchEnabled) { resetKeyRepeatLocked(); } //如果分发冻结了,则不再处理超时和分发事件的工作,直接返回 if (mDispatchFrozen) { return; } // 优化App切换延迟,当切换超时,则抢占分发,丢弃其他所有即将要处理的事件。 bool isAppSwitchDue = mAppSwitchDueTime <= currentTime; if (mAppSwitchDueTime < *nextWakeupTime) { *nextWakeupTime = mAppSwitchDueTime; } // 开始准备启动一个新的事件,如果我们还没有准备好待处理的事件,则先获取一个待处理的事件 if (! mPendingEvent) { if (mInboundQueue.isEmpty()) {//如果mInboundQueue队列为空,则说明没有输入事件需要处理 if (isAppSwitchDue) { resetPendingAppSwitchLocked(false);// mInboundQueue队列为空,说明我们等待APP切换key不会到来,所以停止等待。 isAppSwitchDue = false; } if (mKeyRepeatState.lastKeyEntry) { if (currentTime >= mKeyRepeatState.nextRepeatTime) { mPendingEvent = synthesizeKeyRepeatLocked(currentTime); } else { if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { *nextWakeupTime = mKeyRepeatState.nextRepeatTime; } } } if (!mPendingEvent) {//没有待处理的事件,直接返回 return; } } else { mPendingEvent = mInboundQueue.dequeueAtHead();//mInboundQueue队列不为空,从mInboundQueue队列中获取输入事件 traceInboundQueueLengthLocked(); } if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { pokeUserActivityLocked(mPendingEvent); } //开始准备分发事件 resetANRTimeoutsLocked();//重置ANR信息,见2.3 } ALOG_ASSERT(mPendingEvent != NULL); bool done = false; DropReason dropReason = DROP_REASON_NOT_DROPPED;//丢弃的原因 if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) { dropReason = DROP_REASON_POLICY;//丢弃原因为策略原因 } else if (!mDispatchEnabled) { dropReason = DROP_REASON_DISABLED;//丢弃原因为禁用 } if (mNextUnblockedEvent == mPendingEvent) { mNextUnblockedEvent = NULL; } ...... case EventEntry::TYPE_KEY: {//按键输入事件 KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); if (isAppSwitchDue) { if (isAppSwitchKeyEventLocked(typedEntry)) { resetPendingAppSwitchLocked(true); isAppSwitchDue = false; } else if (dropReason == DROP_REASON_NOT_DROPPED) { dropReason = DROP_REASON_APP_SWITCH;//丢弃原因为APP切换 } } if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEventLocked(currentTime, typedEntry)) { dropReason = DROP_REASON_STALE; } if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);//分发按键输入事件,见2.4 break; } case EventEntry::TYPE_MOTION: {//触摸事件 MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent); if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { dropReason = DROP_REASON_APP_SWITCH; } if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEventLocked(currentTime, typedEntry)) { dropReason = DROP_REASON_STALE; } if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } default: ALOG_ASSERT(false); break; } //分发操作完成,则进入该分支 if (done) { if (dropReason != DROP_REASON_NOT_DROPPED) { dropInboundEventLocked(mPendingEvent, dropReason);//丢弃事件,见 } mLastDropReason = dropReason; releasePendingEventLocked();//释放待处理的输入事件,见 *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } }
在enqueueInboundEventLocked()的过程中已设置mAppSwitchDueTime等于eventTime加上500ms:
mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
该方法的主要功能有:
mDispatchFrozen用于决定是否冻结事件分发工作是否继续执行;
当事件分发的时间点距离该事件加入mInboundQueue的时间超过了500ms,则认为APP切换超时,即isAppSwitchDue为true;
当mInboundQueue不为空时,则取出头部的事件,放入mPendingEvent中,并重置ANR时间;
根据输入事件的类型,分别调用不同的处理函数,例如按键事件,则调用dispatchKeyLocked方法进行处理;
当事件处理完成(done)了,根据dropReason(默认NOT_DROPPED)来决定是否丢弃事件dropInboundEventLocked;
释放当前正在处理的事件mPendingEvent,即调用releasePendingEventLocked;
2.3 InputDispatcher.resetANRTimeoutsLocked()
void InputDispatcher::resetANRTimeoutsLocked() { //清空超时等待cause和handle,将等待原因改为INPUT_TARGET_WAIT_CAUSE_NONE mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; mInputTargetWaitApplicationHandle.clear(); }
2.4 InputDispatcher.dispatchKeyLocked()
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // 预处理 if (! entry->dispatchInProgress) { if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN && (entry->policyFlags & POLICY_FLAG_TRUSTED) && (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { if (mKeyRepeatState.lastKeyEntry && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { // 产生了重复按键,记录下重复按下的次数,并重置重复按键时间为最大 entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1; resetKeyRepeatLocked(); mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // } else { // 不是重复按键,保存下按键状态,以防后面有重复按键 resetKeyRepeatLocked(); mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout; } mKeyRepeatState.lastKeyEntry = entry;//保存最近按键事件为当前处理的按键事件 entry->refCount += 1;//将按键事件的引用次数加1 } else if (! entry->syntheticRepeat) { resetKeyRepeatLocked(); } if (entry->repeatCount == 1) { entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;//长按标志 } else { entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS; } entry->dispatchInProgress = true; logOutboundKeyDetailsLocked("dispatchKey - ", entry); } // 处理拦截策略请求我们再次尝试处理 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; entry->interceptKeyWakeupTime = 0; } // 让policy尝试拦截这个按键事件 if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {//传递给用户 CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);//将命令放入队列,见2.5 // 如果获取焦点的窗口不为空,则将其作为输入窗口 if (mFocusedWindowHandle != NULL) { commandEntry->inputWindowHandle = mFocusedWindowHandle; } commandEntry->keyEntry = entry; entry->refCount += 1; return false; //等待命令运行 } else { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {//跳过 if (*dropReason == DROP_REASON_NOT_DROPPED) { *dropReason = DROP_REASON_POLICY;//丢弃原因为Policy } } // 如果输入事件丢弃原因不是DROP_REASON_NOT_DROPPED,则清空丢弃的输入事件 if (*dropReason != DROP_REASON_NOT_DROPPED) { setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); return true; } // 验证输入目标 Vector<InputTarget> inputTargets; int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime);//找出获取焦点的窗口,见2.6 if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; } setInjectionResultLocked(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { return true; } addMonitoringTargetsLocked(inputTargets); dispatchEventLocked(currentTime, entry, inputTargets);//分发输入事件,见2.9 return true; }
在分发事件前,会做一些预处理工作,如果出现以下情况,则直接返回,跳过事件分发:
当前时间小于拦截唤醒时间的情况,返回false;
输入事件被Policy拦截了,返回false;
输入事件需要被丢弃的情况,返回true;
寻找聚焦窗口,聚焦窗口还未准备好,返回false;
寻找聚焦窗口失败,则返回true;
2.5 InputDispatcher.postCommandLocked()
InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { CommandEntry* commandEntry = new CommandEntry(command);//创建新的CommandEntry mCommandQueue.enqueueAtTail(commandEntry);//将CommandEntry放入到队列的尾部 return commandEntry;//返回CommandEntry } InputDispatcher::CommandEntry::CommandEntry(Command command) : command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0), seq(0), handled(false) { } // Command类型定义 typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry);
postCommandLocked()方法的主要作用是将创建一个CommandEntry,并把CommandEntry放入到命令队列尾部,然后等待执行,最后返回一个CommandEntry。
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( CommandEntry* commandEntry) { KeyEntry* entry = commandEntry->keyEntry; KeyEvent event; initializeKeyEvent(&event, entry); mLock.unlock(); nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, &event, entry->policyFlags);//调用到InputManagerService的interceptKeyBeforeDispatching()方法。 mLock.lock(); if (delay < 0) {// delay小于0 entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;//跳过拦截 } else if (!delay) {//delay等于0 entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;//继续执行 } else {//delay大于0 entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;//下次再尝试 entry->interceptKeyWakeupTime = now() + delay;//拦截唤醒事件 } entry->release(); }
doInterceptKeyBeforeDispatchingLockedInterruptible方法最终会调用到Java层的InputManagerService的interceptKeyBeforeDispatching()方法进行拦截处理,并把拦截结果反馈回来。
2.6 InputDispatcher.findFocusedWindowTargetsLocked()
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { int32_t injectionResult; String8 reason; //如果当前没有聚焦的窗口以及聚焦的应用,则丢弃该输入事件 if (mFocusedWindowHandle == NULL) { if (mFocusedApplicationHandle != NULL) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, NULL, nextWakeupTime, "Waiting because no window has focus but there is a " "focused application that may eventually add a window " "when it finishes starting up.");//目标窗口还没有准备好,见2.7 goto Unresponsive; } ALOGI("Dropping event because there is no focused window or focused application."); injectionResult = INPUT_EVENT_INJECTION_FAILED;//返回失败 goto Failed; } // 权限检查 if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; goto Failed; } // 检查窗口是否准备好了接收更多输入 reason = checkWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry, "focused"); if (!reason.isEmpty()) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());//目标窗口还没有准备好,见2.7 goto Unresponsive; } injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;//成功 addWindowTargetLocked(mFocusedWindowHandle, InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0), inputTargets);//将聚焦的窗口添加到inputTargets数组中,见2.8 // 处理失败的情况 Failed: Unresponsive: nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); updateDispatchStatisticsLocked(currentTime, entry,injectionResult, timeSpentWaitingForApplication); return injectionResult;//返回处理结果 }
在findFocusedWindowTargetsLocked()方法中,首先查询当前是否有聚焦的窗口,然后再检查权限,检查窗口是否准备好了接收更多输入,并将聚焦的窗口添加到InputTargets数组中等待处理,最后返回处理结果。
此处的mFocusedWindowHandle是在注册输入通道时,在InputDispatcher.setInputWindows()方法中设置的。
2.7 InputDispatcher.handleTargetsNotReadyLocked()
int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, const sp<InputApplicationHandle>& applicationHandle, const sp<InputWindowHandle>& windowHandle, nsecs_t* nextWakeupTime, const char* reason) { // 1.如果当前没有聚焦窗口,也没有聚焦的应用 if (applicationHandle == NULL && windowHandle == NULL) { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {//如果等待的原因不是聚焦窗口还未准备好 mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY;//更新等待原因为聚焦窗口还未准备好 mInputTargetWaitStartTime = currentTime;//更新等待开始时间为当前时间 mInputTargetWaitTimeoutTime = LONG_LONG_MAX;//更新等待超时时间 mInputTargetWaitTimeoutExpired = false; mInputTargetWaitApplicationHandle.clear(); } }else {//2.有聚焦窗口或者有聚焦的应用 if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {//等待原因不是应用还未准备就绪 nsecs_t timeout; if (windowHandle != NULL) {//存在聚焦窗口 timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);//获取聚焦窗口的分发超时时间 } else if (applicationHandle != NULL) {//存在聚焦应用 timeout = applicationHandle->getDispatchingTimeout( DEFAULT_INPUT_DISPATCHING_TIMEOUT);//获取聚焦应用的分发超时时间 } else { timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;//默认的分发超时时间为5s } mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;//更新等待原因为聚焦应用还未准备好 mInputTargetWaitStartTime = currentTime;//更新等待开始时间为当前时间 mInputTargetWaitTimeoutTime = currentTime + timeout;//更新等待超时时间 mInputTargetWaitTimeoutExpired = false; mInputTargetWaitApplicationHandle.clear(); // 聚焦窗口不为空 if (windowHandle != NULL) { mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;//更新聚焦应用为聚焦窗口所属的应用 } if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) { mInputTargetWaitApplicationHandle = applicationHandle;//更新等待处理的应用为聚焦应用 } } } //等待超时了 if (mInputTargetWaitTimeoutExpired) { return INPUT_EVENT_INJECTION_TIMED_OUT;//返回超时原因 } //如果当前时间大于输入目标等待超时时间,即当超时5s时进入ANR处理流程 if (currentTime >= mInputTargetWaitTimeoutTime) { onANRLocked(currentTime, applicationHandle, windowHandle, entry->eventTime, mInputTargetWaitStartTime, reason);//调用ANR处理流程,见 *nextWakeupTime = LONG_LONG_MIN;//强制立刻执行轮询来执行ANR策略 return INPUT_EVENT_INJECTION_PENDING;//返回需要等待处理 } else { if (mInputTargetWaitTimeoutTime < *nextWakeupTime) { *nextWakeupTime = mInputTargetWaitTimeoutTime;//更新下次唤醒时间 } return INPUT_EVENT_INJECTION_PENDING;//返回需要等待处理 } }
此处的mInputTargetWaitTimeoutTime是当前时间戳加上5s的超时时间,并设置mInputTargetWaitCause为INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY表示等待的原因是由于应用还未准备就绪。当下次调用handleTargetsNotReadyLocked()方法时,如果等待的原因还是INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY,并且等待时间超过5s钟,说明发生了ANR,则触发ANR处理流程。在2.3中的resetANRTimeoutsLocked()方法,会将等待原因更新为INPUT_TARGET_WAIT_CAUSE_NONE。
那么ANR的时间区间是指在事件分发过程中执行findFocusedWindowTargetsLocked()开始,到下一次执行resetANRTimeoutsLocked()的时间区间。如果时间区间超过了5s,则会触发ANR执行过程。如果没有发生ANR,则通过addWindowTargetLocked()方法将该事件添加到inputTargets中。
2.8 InputDispatcher.addWindowTargetLocked()
void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets) { inputTargets.push(); const InputWindowInfo* windowInfo = windowHandle->getInfo(); InputTarget& target = inputTargets.editTop(); target.inputChannel = windowInfo->inputChannel; target.flags = targetFlags; target.xOffset = - windowInfo->frameLeft; target.yOffset = - windowInfo->frameTop; target.scaleFactor = windowInfo->scaleFactor; target.pointerIds = pointerIds; }
该函数的主要作用是将当前聚焦窗口mFocusedWindowHandle的inputChannel传递到inputTarget。
通过findFocusedWindowTargetsLocked()方法找到了聚焦的窗口后,返回到2.4,继续事件的分发过程,调用dispatchEventLocked()方法。
2.9 InputDispatcher.dispatchEventLocked()
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) { ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true pokeUserActivityLocked(eventEntry);//见2.10 for (size_t i = 0; i < inputTargets.size(); i++) { const InputTarget& inputTarget = inputTargets.itemAt(i);//获取输入目标 ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);//获取连接索引,见2.11 if (connectionIndex >= 0) { sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);//根据索引找到连接 prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);//找到目标连接,见2.12 } } }
该方法的主要作用是遍历inputTargets数组,找到能接收eventEntry的inputTargets。
2.10 InputDispatcher.pokeUserActivityLocked()
void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { if (mFocusedWindowHandle != NULL) { const InputWindowInfo* info = mFocusedWindowHandle->getInfo();//获取聚焦窗口信息 if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) { return; } } int32_t eventType = USER_ACTIVITY_EVENT_OTHER; switch (eventEntry->type) { case EventEntry::TYPE_MOTION: {//触摸事件 const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry); if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { return; } if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { eventType = USER_ACTIVITY_EVENT_TOUCH; } break; } case EventEntry::TYPE_KEY: {//按键事件 const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry); if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) {//取消了 return; } eventType = USER_ACTIVITY_EVENT_BUTTON; break; } } CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doPokeUserActivityLockedInterruptible);//放入任务队列中,随后执行InputDispatcher的doPokeUserActivityLockedInterruptible方法 commandEntry->eventTime = eventEntry->eventTime; commandEntry->userActivityEventType = eventType; }
该方法的主要作用是创建一个doPokeUserActivityLockedInterruptible的任务,并把它放入任务队列中。
void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) { mLock.unlock(); mPolicy->pokeUserActivity(commandEntry->eventTime, commandEntry->userActivityEventType);//此处的mPolicy是NativeInputManager mLock.lock(); }
doPokeUserActivityLockedInterruptible()方法会调用NativeInputManager的pokeUserActivity()方法,最终会调用到Java层的PowerManagerService的userActivityFromNative()方法。
2.11 InputDispatcher.getConnectionIndexLocked()
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) { ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());//根据输入通道的文件描述符获取连接索引 if (connectionIndex >= 0) { sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->inputChannel.get() == inputChannel.get()) {//如果输入通道相同,则返回索引 return connectionIndex; } } return -1; }
该方法的主要是根据inputChannel的Fd获取连接索引,然后根据索引获取连接,并返回索引。
2.12 InputDispatcher.prepareDispatchCycleLocked()
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { // 如果连接状态不正常,则忽略该事件 if (connection->status != Connection::STATUS_NORMAL) { return; } // 将需要分发的eventEntry放入队列中,见2.13 enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget); }
2.13 InputDispatcher.enqueueDispatchEntriesLocked()
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { bool wasEmpty = connection->outboundQueue.isEmpty();//Connection的outboundQueue队列是否为空 //1.根据请求模式,将eventEntry放入队列中 enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);//见2.14 enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_OUTSIDE); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_IS); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); // 2.如果outboundQueue队列先前为空,但现在不为空了,则执行该过程,见2.15 if (wasEmpty && !connection->outboundQueue.isEmpty()) { startDispatchCycleLocked(currentTime, connection); } }
该方法的主要功能是根据请求模式,将eventEntry放入队列中。如果outboundQueue队列先前为空,但现在不为空了,则执行startDispatchCycleLocked()方法。
2.14 InputDispatcher.enqueueDispatchEntryLocked()
void InputDispatcher::enqueueDispatchEntryLocked( const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode) { int32_t inputTargetFlags = inputTarget->flags;//获取输入目标的分发模式 if (!(inputTargetFlags & dispatchMode)) {//如果模式不匹配,则直接返回 return; } inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode; DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, inputTarget->scaleFactor);//创建一个新的DispatchEntry,将DispatchEntry放入到outboundQueue队列中。 switch (eventEntry->type) { case EventEntry::TYPE_KEY: {//按键事件 KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); dispatchEntry->resolvedAction = keyEntry->action; dispatchEntry->resolvedFlags = keyEntry->flags; if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { delete dispatchEntry; return; // skip the inconsistent event } break; } ....... } ..... if (dispatchEntry->hasForegroundTarget()) { incrementPendingForegroundDispatchesLocked(eventEntry); } connection->outboundQueue.enqueueAtTail(dispatchEntry);//将DispatchEntry放入到outboundQueue队列 traceOutboundQueueLengthLocked(connection); }
该方法的主要功能是
根据dispatchMode来决定是否需要添加到outboundQueue队列中;
根据EventEntry,来生成DispatcherEntry事件;
将dispatchEntry加入到connection的outbound队列;
可以看到,从2.2到2.14过程,主要是将InputDispatcher的mInboundQueue中的事件取出来后,然后寻找到目标窗口Window后,将EventEntry封装成DispatcherEntry事件,加入到connection的outbound队列中。
2.15 InputDispatcher.startDispatchCycleLocked()
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) { while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.isEmpty()) {//如果连接的状态是正常的,并且outboundQueue队列不为空 DispatchEntry* dispatchEntry = connection->outboundQueue.head;//获取outboundQueue队列首部的DispatchEntry dispatchEntry->deliveryTime = currentTime; // Publish the event. status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry;//获取EventEntry switch (eventEntry->type) { case EventEntry::TYPE_KEY: { KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); // Publish the key event. status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId, keyEntry->source, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, keyEntry->keyCode, keyEntry->scanCode, keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, keyEntry->eventTime);//发布按键事件,见2.16 break; } ...... } // 检查结果,处理发布失败的情况 if (status) { if (status == WOULD_BLOCK) {//如果结果是阻塞的 if (connection->waitQueue.isEmpty()) {//等待队列为空 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(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);//停止分发事件 } else { // 管道已经满了,我们在等待应用结束处理一些输入事件 connection->inputPublisherBlocked = true; } } else { ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " "status=%d", connection->getInputChannelName(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);//停止分发事件 } return; } connection->outboundQueue.dequeue(dispatchEntry);//将dispatchEntry出队列 traceOutboundQueueLengthLocked(connection); connection->waitQueue.enqueueAtTail(dispatchEntry);//将dispatchEntry放入等待队列 traceWaitQueueLengthLocked(connection); } }
该方法的主要功能是从outboundQueue队列中取出dispatchEntry事件,然后发布事件,最后将dispatchEntry事件放入到等待队列中。abortBrokenDispatchCycleLocked()方法最终会调用到Java层的InputManagerService的notifyInputChannelBroken()方法。
2.16 InputPublisher.publishKeyEvent()
status_t InputPublisher::publishKeyEvent( uint32_t seq, int32_t deviceId, int32_t source, 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 (!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.deviceId = deviceId; msg.body.key.source = source; 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的sendMessage方法,见2.17 }
2.17 InputChannel.sendMessage()
status_t InputChannel::sendMessage(const InputMessage* msg) { size_t msgLength = msg->size();//获取消息的大小 ssize_t nWrite; do { nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);//通过Socket发送消息到InputDispatcher的输入通道 } while (nWrite == -1 && errno == EINTR); if (nWrite < 0) {//处理失败的情况 int error = errno; 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) { return DEAD_OBJECT; } return OK;//返回成功 }
在应用程序注册输入消息接收通道的文章中,介绍了输入通道的注册过程中,会创建一个套接字对socketpair,其中一端为server端套接字,保存在system_server中的WindowState的mInputChannel,另外一端为client端套接字,通过Binder机制回传到远程进程的UI主线程ViewRootImpl的mInputChannel。这个socketpair创建了一对匿名的已经连接的套接字,可以实现在同一个文件描述符中进行读写的功能。在Linux中,完全可以把这一对socket当成pipe返回的文件描述符一样使用,唯一的区别就是这一对文件描述符中的任何一个都可读和可写。与一般的管道相区别的是,套接字对建立的通道是双向的,即每一端都可以进行读写。当在socketpair一端写入时,只能在另外一端读出,而在写入端读出时会阻塞。
server端套接字和client端套接字都通过Looper->addFd()方法添加到文件描述符监控范围,分别在InputDispatcher的registerInputChannel()方法和NativeInputEventReceiver的setFdEvents()方法中实现。当套接字对中的套接字有数据可读时,则唤醒epoll_wait等待状态,调用回调函数进行相应的处理。
//server端套接字注册监听 status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { ...... sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);//创建一个新的连接 int fd = inputChannel->getFd();// 获取输入通道的文件描述符 mConnectionsByFd.add(fd, connection);// 将连接按文件描述符保存 mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);// 通过Looper的addFd方法,将server端套接字文件描述符添加到Looper的监控中,并设置回调处理函数为handleReceiveCallback方法。 mLooper->wake();//唤醒操作 return OK; } //client端套接字注册监听 void NativeInputEventReceiver::setFdEvents(int events) { if (mFdEvents != events) { mFdEvents = events;//更新文件描述符支持的操作 int fd = mInputConsumer.getChannel()->getFd();//获取输入通道的文件描述符 if (events) { mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);//将client端套接字文件描述符添加到消息队列关联Looper循环中,监听events事件,并设置事件回调处理对象为NativeInputEventReceiver。 } else { mMessageQueue->getLooper()->removeFd(fd); } } }
在InputDispatcher的registerInputChannel()和NativeInputEventReceiver的setFdEvents()方法都是监控了套接字的输入事件(ALOOPER_EVENT_INPUT),因此当套接字中有数据到来时,将会唤醒epoll_wait上等待的操作,调用回调方法来处理数据。因为server端套接字和client端套接字是socketpair的两端,只能一端写入,另外一端读出。因此当通过InputDispatcher的mChannel的sendMessage()方法发送消息时,即在server端套接字写入数据,只能在client端套接字读取出来。所以将唤醒在epoll_wait上等待的操作,调用client端回调方法NativeInputEventReceiver.handleEvent()来处理数据。
2.18 NativeInputEventReceiver.handleEvent()
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) { //错误的输出 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. " "events=0x%x", getInputChannelName(), events); } return 0;//移除回调 } if (events & ALOOPER_EVENT_INPUT) {//有数据可读 JNIEnv* env = AndroidRuntime::getJNIEnv(); status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);//消费输入事件,见2.19 mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");//清除 return status == OK || status == NO_MEMORY ? 1 : 0; } if (events & ALOOPER_EVENT_OUTPUT) {//有数据可写 for (size_t i = 0; i < mFinishQueue.size(); i++) { const Finish& finish = mFinishQueue.itemAt(i); status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);//发送结束信号,见 if (status) { mFinishQueue.removeItemsAt(0, i); if (status == WOULD_BLOCK) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.", getInputChannelName(), i, mFinishQueue.size()); } return 1; // 保留callback,稍后重试 } ALOGW("Failed to send finished signal on channel '%s'. status=%d", getInputChannelName(), status); if (status != DEAD_OBJECT) { JNIEnv* env = AndroidRuntime::getJNIEnv(); String8 message; message.appendFormat("Failed to finish input event. status=%d", status); jniThrowRuntimeException(env, message.string()); mMessageQueue->raiseAndClearException(env, "finishInputEvent"); } return 0; // 移除callback } } mFinishQueue.clear();//情况队列 setFdEvents(ALOOPER_EVENT_INPUT);//监控输入 return 1; } ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " "events=0x%x", getInputChannelName(), events); return 1; }
在NativeInputEventReceiver的会调用函数handleEvent()主要是根据event类型,进行相应的处理。
event是ALOOPER_EVENT_INPUT时,即有数据可读时,调用consumeEvents()方法进行处理;
event是ALOOPER_EVENT_OUTPUT时,即有数据可写时,调用InputConsumer的sendFinishedSignal()方法进行处理;
2.19 NativeInputEventReceiver.consumeEvents()
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) { if (consumeBatches) { mBatchedInputEventPending = false; } if (outConsumedBatch) { *outConsumedBatch = false; } ScopedLocalRef<jobject> receiverObj(env, NULL); bool skipCallbacks = false; for (;;) { uint32_t seq; InputEvent* inputEvent; status_t status = mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent);// 调用InputConsumer的consume()方法,见2.20 if (status) { if (status == WOULD_BLOCK) { ...... return OK;//消费完成 } ...... return status;//消费失败 } assert(inputEvent); if (!skipCallbacks) { if (!receiverObj.get()) { receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal)); if (!receiverObj.get()) { ALOGW("channel '%s' ~ Receiver object was finalized " "without being disposed.", getInputChannelName()); return DEAD_OBJECT; } } jobject inputEventObj; switch (inputEvent->getType()) {//输入事件的类型 case AINPUT_EVENT_TYPE_KEY://按键事件 inputEventObj = android_view_KeyEvent_fromNative(env, static_cast<KeyEvent*>(inputEvent));//由Native层的InputEvent来生成Java层的输入事件,见2.22 break; case AINPUT_EVENT_TYPE_MOTION: {//触摸事件 MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent); if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) { *outConsumedBatch = true; } inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);//由Native层的MotionEvent来生成Java层的输入事件 break; } default: assert(false); // InputConsumer should prevent this from ever happening inputEventObj = NULL; } if (inputEventObj) {//输入事件不为空 env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);//调用Java层的InputEventReceiver的dispatchInputEvent()方法,见2.23 if (env->ExceptionCheck()) { ALOGE("Exception dispatching input event."); skipCallbacks = true; } env->DeleteLocalRef(inputEventObj); } else { ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName()); skipCallbacks = true; } } if (skipCallbacks) {//跳过执行回调函数 mInputConsumer.sendFinishedSignal(seq, false); } } }
在该方法中,主要完成了以下几件事情:
调用InputConsumer的consume()方法来获取输入事件的序列化seq以及inputEvent实例;
根据输入事件的类型,生成Java层对应的输入事件;
调用Java层的InputEventReceiver的dispatchInputEvent()方法进行分发处理;
根据是否发生了异常,决定是否需要调用sendFinishedSignal()向InputDispatcher发送完成信号。
2.20 InputConsumer.consume()
status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { *outSeq = 0; *outEvent = NULL; // 获取下一个输入消息,一直循环直至返回一个输入事件,或者没有输入事件可以接收 while (!*outEvent) { if (mMsgDeferred){ mMsgDeferred = false; }else { status_t result = mChannel->receiveMessage(&mMsg);//接收一个新的消息,见2.21 if (result) { if (consumeBatches || result != WOULD_BLOCK) { result = consumeBatch(factory, frameTime, outSeq, outEvent); if (*outEvent) { break; } } return result;//返回失败 } } switch (mMsg.header.type) { case InputMessage::TYPE_KEY: {//按键事件 KeyEvent* keyEvent = factory->createKeyEvent();//创建一个keyEvent if (!keyEvent) return NO_MEMORY; initializeKeyEvent(keyEvent, &mMsg);//初始化KeyEvent *outSeq = mMsg.body.key.seq; *outEvent = keyEvent; break; } case AINPUT_EVENT_TYPE_MOTION: {//触摸事件 ..... } default: return UNKNOWN_ERROR; } } return OK; }
在InputConsumer的consume()方法中,首先通过InputChannel的receiveMessage()方法来接收输入信息,然后根据输入信息的类型,创建相应的输入事件。例如按键事件类型,则创建KeyEvent事件。最后将输入事件以及序列号分别赋值给outEvent和outSeq返回。
2.21 InputChannel.receiveMessage()
status_t InputChannel::receiveMessage(InputMessage* msg) { ssize_t nRead; do { nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);//循环从套接字中读取数据,放入到msg中 } while (nRead == -1 && errno == EINTR); if (nRead < 0) { .... return -error; } if (nRead == 0) { return DEAD_OBJECT; } if (!msg->isValid(nRead)) { return BAD_VALUE; } return OK; }
该方法的主要作用是从套接字中循环读取数据,并把数据放入到类型为InputMessage的msg中。消息的发送是在2.17中的InputChannel的sendMessage()方法中,发送的数据类型也是InputMessage。
当套接字中获取到输入事件数据后,回到2.19中,继续创建Java层的输入事件。
2.22 android_view_KeyEvent_fromNative()
jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) { jobject eventObj = env->CallStaticObjectMethod(gKeyEventClassInfo.clazz, gKeyEventClassInfo.obtain, nanoseconds_to_milliseconds(event->getDownTime()), nanoseconds_to_milliseconds(event->getEventTime()), event->getAction(), event->getKeyCode(), event->getRepeatCount(), event->getMetaState(), event->getDeviceId(), event->getScanCode(), event->getFlags(), event->getSource(), NULL); if (env->ExceptionCheck()) { ALOGE("An exception occurred while obtaining a key event."); LOGE_EX(env); env->ExceptionClear(); return NULL; } return eventObj; }
android_view_KeyEvent_fromNative()方法定义在framework/core/jni/android_view_KeyEvent.cpp文件中,其主要作用是调用Java层的KeyEvent的obtain()方法创建一个KeyEvent对象,然后将keyEvent对象返回。
public static KeyEvent obtain(long downTime, long eventTime, int action, int code, int repeat, int metaState, int deviceId, int scancode, int flags, int source, String characters) { KeyEvent ev = obtain(); ev.mDownTime = downTime; ev.mEventTime = eventTime; ev.mAction = action; ev.mKeyCode = code; ev.mRepeatCount = repeat; ev.mMetaState = metaState; ev.mDeviceId = deviceId; ev.mScanCode = scancode; ev.mFlags = flags; ev.mSource = source; ev.mCharacters = characters; return ev; }
当返回KeyEvent对象后,回到2.19中,继续通过JNI调用Java层的InputEventReceiver的dispatchInputEvent()方法进行分发处理;
2.23 InputEventReceiver.dispatchInputEvent()
private void dispatchInputEvent(int seq, InputEvent event) { mSeqMap.put(event.getSequenceNumber(), seq);//映射InputEvent的序列号码到分发序列号 onInputEvent(event);//调用ViewRootImpl内部类WindowInputEventReceiver的onInputEvent()方法,见2.24 }
InputEventReceiver是一个抽象类,具体的实现类是ViewRootImpl内部类WindowInputEventReceiver,其在ViewRootImpl调用setView()方法注册输入通道时被初始化的。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { ...... mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper()); ...... }
2.24 WindowInputEventReceiver.onInputEvent()
final class WindowInputEventReceiver extends InputEventReceiver { ...... @Override public void onInputEvent(InputEvent event) { enqueueInputEvent(event, this, 0, true);//见2.25 } ...... }
2.25 ViewRootImpl.enqueueInputEvent()
void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { adjustInputEventForCompatibility(event); QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);//获取InputEvent事件,见2.26 QueuedInputEvent last = mPendingInputEventTail;//指向待处理事件的尾部 if (last == null) { mPendingInputEventHead = q; mPendingInputEventTail = q; } else { last.mNext = q;//添加到待处理输入事件尾部 mPendingInputEventTail = q; } mPendingInputEventCount += 1;//待处理输入事件加1 if (processImmediately) {//立即处理 doProcessInputEvents();//处理输入事件,见2.27 } else { scheduleProcessInputEvents(); } }
2.26 ViewRootImpl.obtainQueuedInputEvent()
private QueuedInputEvent obtainQueuedInputEvent(InputEvent event, InputEventReceiver receiver, int flags) { QueuedInputEvent q = mQueuedInputEventPool;//对象池 if (q != null) {//如果存在的话,直接从中取一个出来使用 mQueuedInputEventPoolSize -= 1; mQueuedInputEventPool = q.mNext; q.mNext = null; } else { q = new QueuedInputEvent(); } //将event和receiver和flags进行赋值 q.mEvent = event; q.mReceiver = receiver; q.mFlags = flags; return q; }
2.27 ViewRootImpl.doProcessInputEvents()
void doProcessInputEvents() { while (mPendingInputEventHead != null) { QueuedInputEvent q = mPendingInputEventHead; mPendingInputEventHead = q.mNext; if (mPendingInputEventHead == null) { mPendingInputEventTail = null; } q.mNext = null; mPendingInputEventCount -= 1;//待处理事件数量减1 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName, mPendingInputEventCount); long eventTime = q.mEvent.getEventTimeNano();//记录事件处理时间 long oldestEventTime = eventTime; if (q.mEvent instanceof MotionEvent) {//触摸事件 MotionEvent me = (MotionEvent)q.mEvent; if (me.getHistorySize() > 0) { oldestEventTime = me.getHistoricalEventTimeNano(0); } } mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);//更新输入事件最新和最老的时间 deliverInputEvent(q);//分发事件,见2.28 } // 已经处理完所有的输入事件,可以清空等待标志 if (mProcessInputEventsScheduled) { mProcessInputEventsScheduled = false; mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS); } }
2.28 ViewRootImpl.deliverInputEvent()
private void deliverInputEvent(QueuedInputEvent q) { if (mInputEventConsistencyVerifier != null) {//调试目的 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0); } InputStage stage; if (q.shouldSendToSynthesizer()) { stage = mSyntheticInputStage; } else { stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; } if (stage != null) { stage.deliver(q);//分发给最终的处理该事件的窗口 } else { finishInputEvent(q);//结束输入事件处理,见2.29 } }
这里的state是mFirstInputStage,mFirstInputStage的初始化在ViewRootImpl的setView()方法中初始化的。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { ....... //初始化输入管道 CharSequence counterSuffix = attrs.getTitle(); mSyntheticInputStage = new SyntheticInputStage(); InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage); InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage, "aq:native-post-ime:" + counterSuffix); InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage); InputStage imeStage = new ImeInputStage(earlyPostImeStage, "aq:ime:" + counterSuffix); InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage); InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage, "aq:native-pre-ime:" + counterSuffix); mFirstInputStage = nativePreImeStage; mFirstPostImeInputStage = earlyPostImeStage; }
可以看到mFirstInputStage指向的是NativePreImeInputStage,而NativePreImeInputStage由持有ViewPreImeInputStage,ViewPreImeInputStage又持有ImeInputStage,这样一层层包装,形成了一个调用链。它们都是InputState的子类,通过next变量连接起来,就像一个单向链表。经过层层的调用,最终会传递给ViewPostImeInputStage处理。
abstract class InputStage { ...... private final InputStage mNext; public InputStage(InputStage next) { mNext = next; } public final void deliver(QueuedInputEvent q) { if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) { forward(q); } else if (shouldDropInputEvent(q)) { finish(q, false); } else { apply(q, onProcess(q)); } } }
当调用state的deliver方法时,都会调用其父类的deliver方法,根据输入事件的不同状态选择不同的处理方式。
输入事件处理结果了,则调用forward()方法;
输入事件需要被丢弃,则调用finish()方法;
输入事件需要处理,则调用apply()方法,在调用apply()方法之前,首先要调用onProcess()方法进行处理,根据处理结果再决定下一步该如何处理;
在ViewPostImeInputStage类中,实现了onProcess()方法,因此会先调用ViewPostImeInputStage的onProcess()方法进行处理。
ViewPostImeInputStage.onProcess()
final class ViewPostImeInputStage extends InputStage { public ViewPostImeInputStage(InputStage next) { super(next); } @Override protected int onProcess(QueuedInputEvent q) { if (q.mEvent instanceof KeyEvent) {//按键事件 return processKeyEvent(q);//调用 } else { final int source = q.mEvent.getSource(); if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { return processPointerEvent(q); } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { return processTrackballEvent(q); } else { return processGenericMotionEvent(q); } } } private int processKeyEvent(QueuedInputEvent q) { final KeyEvent event = (KeyEvent)q.mEvent; // Deliver the key to the view hierarchy. if (mView.dispatchKeyEvent(event)) {//调用ViewRootImpl中DecorView的dispatchKeyEvent()方法。 return FINISH_HANDLED; } ...... } }
可以看到,在ViewPostImeInputStage的onProcess()方法中,会调用到processKeyEvent()方法,在processKeyEvent()方法中,会调用ViewRootImpl中成员变量mView的dispatchKeyEvent()方法。mView是在ViewRootImpl的setView()方法中进行赋值,该View是PhoneWindow的DecorView。DecorView是一个Activity最顶层的View,所有的事件分发都是从这个View开始,逐层的分发到View层级中的各个View。
至此,完成了输入事件从InputDispatcher线程分发到应用程序激活Activity的窗口过程。输入事件处理完成后,还需要通知InputDispatcher,继续处理下一个事件的分发。输入事件处理完成后,会调用ViewRootImpl的finishInputEvent()方法。
2.29 ViewRootImpl.finishInputEvent()
private void finishInputEvent(QueuedInputEvent q) { if (q.mReceiver != null) { boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0; q.mReceiver.finishInputEvent(q.mEvent, handled);//调用InputEventReceiver的finishInputEvent(),见2.30 } else { q.mEvent.recycleIfNeededAfterDispatch(); } recycleQueuedInputEvent(q); }
当收到输入事件时,需要处理这个输入事件,然后调用finishInputEvent()方法来反馈这个输入事件是否已经被处理了。在调用finishInputEvent()方法之前,不会接收新的输入事件。
2.30 InputEventReceiver.finishInputEvent()
public final void finishInputEvent(InputEvent event, boolean handled) { if (mReceiverPtr == 0) { ...... } else { int index = mSeqMap.indexOfKey(event.getSequenceNumber()); if (index < 0) { ....... } else { int seq = mSeqMap.valueAt(index); mSeqMap.removeAt(index); nativeFinishInputEvent(mReceiverPtr, seq, handled);//调用native方法,见2.31 } } event.recycleIfNeededAfterDispatch(); }
nativeFinishInputEvent()方法经过层层调用,会调用android_view_InputEventReceiver类的nativeFinishInputEvent()方法。
2.31 nativeFinishInputEvent()
static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr, jint seq, jboolean handled) { sp<NativeInputEventReceiver> receiver = reinterpret_cast<NativeInputEventReceiver*>(receiverPtr); status_t status = receiver->finishInputEvent(seq, handled);//调用NativeInputEventReceiver的finishInputEvent()方法,见2.32 if (status && status != DEAD_OBJECT) { String8 message; message.appendFormat("Failed to finish input event. status=%d", status); jniThrowRuntimeException(env, message.string()); } }
2.32 NativeInputEventReceiver.finishInputEvent()
status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) { ..... status_t status = mInputConsumer.sendFinishedSignal(seq, handled);//调用InputConsumer的sendFinishedSignal()方法,见2.33 if (status) {//异常处理 if (status == WOULD_BLOCK) { Finish finish; finish.seq = seq; finish.handled = handled; mFinishQueue.add(finish); if (mFinishQueue.size() == 1) { setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT); } return OK; } } return status; }
2.33 InputConsumer.sendFinishedSignal()
status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) { if (!seq) { return BAD_VALUE; } size_t seqChainCount = mSeqChains.size();//批量处理 if (seqChainCount) { uint32_t currentSeq = seq; uint32_t chainSeqs[seqChainCount]; size_t chainIndex = 0; //批量处理 for (size_t i = seqChainCount; i-- > 0; ) { const SeqChain& seqChain = mSeqChains.itemAt(i); if (seqChain.seq == currentSeq) { currentSeq = seqChain.chain; chainSeqs[chainIndex++] = currentSeq; mSeqChains.removeAt(i); } } status_t status = OK; while (!status && chainIndex-- > 0) { status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);//发送结束信号,见2.34 } if (status) { // 发生了错误,重新构建这个处理链 do { SeqChain seqChain; seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq; seqChain.chain = chainSeqs[chainIndex]; mSeqChains.push(seqChain); } while (chainIndex-- > 0); return status; } } return sendUnchainedFinishedSignal(seq, handled); }
2.34 InputConsumer.sendUnchainedFinishedSignal()
status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) { InputMessage msg; msg.header.type = InputMessage::TYPE_FINISHED; msg.body.finished.seq = seq; msg.body.finished.handled = handled; return mChannel->sendMessage(&msg);//通过InputChannel发送Socket消息到InputDispatcher,消息类型为TYPE_FINISHED。 }
通过InputChannel的sendMessage()方法,可以将TYPE_FINISHED类型的输入消息发送到InputDispatcher线程。和之前2.17处理流程一样,只是此处是往client端套接字写入消息。此时在server端epoll_wait上等待输入消息的线程会被唤醒,调用相应的回调方法:InputDispatcher的handleReceiveCallback()方法。
2.35 InputDispatcher.handleReceiveCallback()
int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { InputDispatcher* d = static_cast<InputDispatcher*>(data);//获取传递的数据 { // acquire lock AutoMutex _l(d->mLock); ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd); if (connectionIndex < 0) {//没有找到 ALOGE("Received spurious receive callback for unknown input channel. " "fd=%d, events=0x%x", fd, events); return 0; // remove the callback } bool notify; sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);//获得连接 if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {//不是错误或者挂起 if (!(events & ALOOPER_EVENT_INPUT)) {// 不是输入事件 ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " "events=0x%x", connection->getInputChannelName(), events); return 1; } nsecs_t currentTime = now();//当前时间 bool gotOne = false; status_t status; for (;;) { uint32_t seq; bool handled; status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);//循环等待接收结束信号,见2.36 if (status) { break; } d->finishDispatchCycleLocked(currentTime, connection, seq, handled);//结束分发操作,见2.37 gotOne = true; } if (gotOne) { d->runCommandsLockedInterruptible();//执行任务,见2.40 if (status == WOULD_BLOCK) { return 1; } } notify = status != DEAD_OBJECT || !connection->monitor; }else{ notify = !connection->monitor; } d->unregisterInputChannelLocked(connection->inputChannel, notify);//反注册输入通道 return 0;//移除回调 } }
当client端套接字写入了消息,会唤醒在server端epoll_wait等待的事件,此时会调用回调函数handleReceiveCallback()方法进行处理,在该方法中,首先循环等待接收结束信号,然后结束分发操作;
2.36 InputPublisher.receiveFinishedSignal()
status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) { InputMessage msg; status_t result = mChannel->receiveMessage(&msg);//调用InputChannel的receiveMessage()方法,接收消息,过程见2.21 if (result) {//结果为空 *outSeq = 0; *outHandled = false; return result; } if (msg.header.type != InputMessage::TYPE_FINISHED) {//消息类型不是结束类型 ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer", mChannel->getName().string(), msg.header.type); return UNKNOWN_ERROR; } *outSeq = msg.body.finished.seq; *outHandled = msg.body.finished.handled; return OK; }
2.37 InputDispatcher.finishDispatchCycleLocked()
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) { connection->inputPublisherBlocked = false; if (connection->status == Connection::STATUS_BROKEN || connection->status == Connection::STATUS_ZOMBIE) { return; } // Notify other system components and prepare to start the next dispatch cycle. //通知其他系统组件并且准备开始下一个分发周期,见2.38 onDispatchCycleFinishedLocked(currentTime, connection, seq, handled); }
2.38 InputDispatcher.onDispatchCycleFinishedLocked()
void InputDispatcher::onDispatchCycleFinishedLocked( nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) { CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);//将任务放入任务队列,随后执行doDispatchCycleFinishedLockedInterruptible,见2.39 commandEntry->connection = connection; commandEntry->eventTime = currentTime; commandEntry->seq = seq; commandEntry->handled = handled; }
2.39 InputDispatcher.doDispatchCycleFinishedLockedInterruptible()
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( CommandEntry* commandEntry) { sp<Connection> connection = commandEntry->connection; nsecs_t finishTime = commandEntry->eventTime; uint32_t seq = commandEntry->seq; bool handled = commandEntry->handled; DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);//寻找等待的DispatchEntry if (dispatchEntry) { nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;//计算事件分发所花费的时间 if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {//1.事件分发时间超过2s String8 msg; msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ", connection->getWindowName(), eventDuration * 0.000001f); dispatchEntry->eventEntry->appendDescription(msg);//打印出所有事件分发时间超过2s中的事件 ALOGI("%s", msg.string()); } bool restartEvent;//是否需要重新处理 if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {//处理按键事件 KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry); restartEvent = afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled); } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {//处理触摸事件 MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry); restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry, handled); } else { restartEvent = false; } // 将事件出队列,并开始处理下一个事件 if (dispatchEntry == connection->findWaitQueueEntry(seq)) { connection->waitQueue.dequeue(dispatchEntry);//2.事件出队列 traceWaitQueueLengthLocked(connection); if (restartEvent && connection->status == Connection::STATUS_NORMAL) {//需要重新处理该事件 connection->outboundQueue.enqueueAtHead(dispatchEntry);//放入输入队列的首部 traceOutboundQueueLengthLocked(connection); } else { releaseDispatchEntryLocked(dispatchEntry);//释放dispatchEntry } } //3.启动下一个循环,见2.15 startDispatchCycleLocked(now(), connection); } }
在该方法中,首先计算事件分发所花费的时间,如果大于2s的话,则打印出该事件;接着将DispatcherEntry事件从等待队列中移除;最后通过startDispatchCycleLocked()方法启动下一个循环。
在2.38中,通过postCommandLocked()方法加入的任务不会理解执行,而是需要通过runCommandsLockedInterruptible()方法来执行任务队列中任务。返回到2.35中,执行完finishDispatchCycleLocked()方法之后,会马上执行runCommandsLockedInterruptible()方法。
2.40 InputDispatcher.runCommandsLockedInterruptible()
bool InputDispatcher::runCommandsLockedInterruptible() { if (mCommandQueue.isEmpty()) {//队列为空,则直接返回 return false; } do { CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();//会去任务队列头部的任务 Command command = commandEntry->command; (this->*command)(commandEntry); //执行任务,此处调用的命令隐式地包含'LockedInterruptible' commandEntry->connection.clear(); delete commandEntry;//删除任务 } while (! mCommandQueue.isEmpty()); return true; }
该方法的逻辑比较简单,只是不断地从mCommandQueue队列取出命令,然后执行直到全部执行完成。 除了doPokeUserActivityLockedInterruptible,还有其他如下命令:
doNotifyANRLockedInterruptible
doInterceptKeyBeforeDispatchingLockedInterruptible
doDispatchCycleFinishedLockedInterruptible
doNotifyInputChannelBrokenLockedInterruptible
doNotifyConfigurationChangedInterruptible
至此,完成了从应用程序通知InputDispatcher,输入事件处理完成了,并启动下一个输入事件处理流程的过程。
3.总结
当InputDispatcher线程从InputReader线程中获取到输入事件后,需要将输入事件分发给应用程序激活的Activity窗口。其中包含了两个过程:从InputDispatcher线程将输入事件分发给应用程序窗口处理,其处理流程见2.1~2.28过程。通过InputChannel的sendMessage()方法往server端套接字写入输入事件消息,唤醒在client端套接字上epoll_wait等待的事件,调用回调方法NativeInputEventReceiver.handleEvent()处理输入事件。通过调用InputChannel的receiveMessage()方法读取InputDispatcher发送的输入事件,最终交给应用程序的窗口处理。
从应用程序处理完输入事件到InputDispatcher线程开启下一个输入事件处理,其处理流程见2.29~2.40过程。通过InputChannel的sendMessage()方法往client端套接字写入输入事件处理完成消息,唤醒在server端套接字上epoll_wait等待的事件,调用回调方法InputDispatcher.handleReceiveCallback()处理输入结束事件。通过startDispatchCycleLocked()方法开始下一个输入事件处理流程;
在server端和client端分别创建了输入通道InputChannel,它们之间是通过一个socketpair连接起来的,socketpair()函数建立的是一对匿名的套接字,可以实现在同一个文件描述符中实现读写功能。socketpair与管道pipe的区别是,socketpair建立的通道是双向的,即每一端都可以进行读写,只是有一点需要注意,在一端写入,只能在另外一端读出,在写入一端读出时,会阻塞。因此我们可以看到,在InputDispatcher线程将输入事件分发给应用程序处理的过程,是在server端套接字写入,只能在client端套接字读出,唤醒的是NativeInputEventReceiver.handleEvent()回调方法。虽然在server端和client端都通过Looper->addFd()方法,监听了套接字描述符中有数据可读的场景,但只有一端套接字描述符会响应,因为socketpair同时只有一端可以读,另外一端只能写。同样的,从应用程序处理完输入事件到InputDispatcher线程开启下一个输入事件的过程,是在client端套接字写入,只能在server端套接字读出,唤醒的是InputDispatcher.handleReceiveCallback()回调方法。
相关文章推荐
- InputManagerService分发输入事件给应用程序(上)
- InputManagerService之事件的初始化与分发
- InputManagerService之事件的初始化与分发
- Android输入事件从读取到分发三:InputDispatcherThread线程分发事件的过程
- Android输入事件从读取到分发四:InputDispatcherThread发送事件到View结构树的过程
- Android5.0 输入系统(一)————InputManagerService服务及相关对象的创建与启动
- InputManagerService分析一:IMS的启动与事件传递
- Android 输入系统(一)InputManagerService
- Android输入事件从读取到分发三:InputDispatcherThread线程分发事件的过程
- 了解Android触摸事件原理(InputManagerService)
- jquery实现input输入框实时输入触发事件
- Android 4.0 事件输入(Event Input)系统
- 添加已有input事件类型上层分发处理
- 协议消息与应用程序事件的统一分发框架
- #632 – 使用PreviewTextInput事件阻止用户输入(Block Input Using PreviewTextInput)
- android 输入法 回调一:IInputMethodWrapper通过MethodCallback来回调InputMethodManagerService方法
- input输入域的事件监听最佳代码
- InputManagerService服务的初始化
- input 输入完成时执行的事件change事件
- INPUT设备输入事件的传递过程