本章节仅以Motion事件分析为主。
InputDispatcher事件派发时序图
InputDispatcher事件处理Code分析
紧接上一篇InputReader分析
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
//判断motion event是否有效
if (!validateMotionEvent(args->action, args->actionButton,
args->pointerCount, args->pointerProperties)) {
return;
}
//事件派发之前,首先向DispatchPolicy获取本事件的派发策略
uint32_t policyFlags = args->policyFlags;
policyFlags |= POLICY_FLAG_TRUSTED;//只要是EventHub的事件都是可信任的
//mPolicy接口的实现类是com_android_server_input_InputManagerService.cpp,其实最终
//的处理是在java层的PhoneWindowManager里
mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);
bool needWake;
{ // acquire lock
mLock.lock();
//此处我的理解是判断事件是否需要过滤,若是需要则会调用filterInputEvent方法
if (shouldSendMotionToInputFilterLocked(args)) {
mLock.unlock();
MotionEvent event;
//使用NotifyMotionArgs参数所保存的事件信息构建一个MotionEvent对象
event.initialize(args->deviceId, args->source, args->action, args->actionButton,
args->flags, args->edgeFlags, args->metaState, args->buttonState,
0, 0, args->xPrecision, args->yPrecision,
args->downTime, args->eventTime,
args->pointerCount, args->pointerProperties, args->pointerCoords);
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
mLock.lock();
}
// Just enqueue a new motion event.
//使用NotifyMotionArgs参数所保存的事件信息构建一个MotionEntry对象
MotionEntry* newEntry = new MotionEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, args->actionButton, args->flags,
args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
args->displayId,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
//将构造的MotionEntry放入派发队列。返回值决定了是否唤醒派发线程
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
if (needWake) {
//唤醒派发线程,即使Looper.pollonce立即返回
**mLooper->wake();**
}
}
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
//唤醒所有的线程,在所有线程被唤醒之前会阻塞在这
mDispatcherIsAliveCondition.broadcast();
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
//此处进行事件派发,传出的参数nextWakeupTime决定了下次派发线程循环执行的时间
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
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);
//此处是比较关键的,它可以说是轮子转动的控制按钮。当调用wake()或者超过定时时间
//或者epoll_wait监听 的fd有epoll_event发生时会唤醒,即立刻返回。
**mLooper->pollOnce(timeoutMillis);**
}
dispatchOnce调用mLooper->pollOnce等待事件的到来。当调用wake的时候会重新执行此方法(原因同InputReader)。
//事件的派发时串行大的,在排在队首的事件完成派发或被丢弃之前,不会对后续事件进行派发
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
//如果InputDispatcher被冻结,则不做任何派发操作。setInputDispatchMode可以让禁用/冻结/正常
//三种状态来回切换
// 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.");
#endif
return;
}
// Optimize latency of app switches.
// Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
// been pressed. When it expires, we preempt dispatch and drop all other pending events.
bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
if (mAppSwitchDueTime < *nextWakeupTime) {
*nextWakeupTime = mAppSwitchDueTime;
}
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) {
if (isAppSwitchDue) {
// 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) {
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// Nothing to do if there is no pending event.
if (!mPendingEvent) {
return;
}
} else {
// Inbound queue has at least one entry.
//从队列头取出一条事件并保存在mPendingEvent中,它表示处于派发过程中的一个
//输入事件。
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
//此处粗略的研究了一下,该处和PMS有关联,此处是为保持屏幕唤醒
pokeUserActivityLocked(mPendingEvent);
}
// Get ready to dispatch the event.
resetANRTimeoutsLocked();
}
......
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
//事件因为Home键没有被及时响应而被丢弃
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;
}
//如果派发完成,无论成功派发还是事件被丢弃都返回true,否则返回false,以便在
//下次循环时再次尝试此事件的派发
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
break;
}
default:
ALOG_ASSERT(false);
break;
}
//如果事件派发完成,则准备派发下一个事件
if (done) {
//如果事件因为某种原因被丢弃,为了保证窗口收到的事件能够保持DOWN/UP,ENTER/EXIT的配对
//还需要对事件进行派发
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);
}
mLastDropReason = dropReason;
//设置mPendingEvent对象为null,使之在下次循环时可以处理派发队列中的下一条事件
releasePendingEventLocked();
//立刻开始下一次循环。如果此时派发队列为空,下次循环调用此函数时会保持
//*nextWakeupTime = LONG_LONG_MAX并直接返回,使得派发线程进入无限期休眠
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
//标记事件已正式进入派发线程
if (! entry->dispatchInProgress) {
entry->dispatchInProgress = true;
logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
// Identify targets.
//列表保存了此事件的派发目标
Vector<InputTarget> inputTargets;
bool conflictingPointerActions = false;
int32_t injectionResult;
//根据Motion事件的类型寻找合适的窗口
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
//对于基于坐标点形式的事件。如触摸屏点击,将根据坐标点、窗口ZOrder与区域寻找目标窗口
injectionResult = findTouchedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
} else {
// Non touch event. (eg. trackball)
//对于其它类型的Motion事件,如轨迹球,将以拥有焦点的窗口作为目标。具体研究可以参考
//findTouchedWindowTargetsLocked
injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
}
//返回PENGDING表明找到了一个窗口。不过如果窗口处于无响应状态,则返回false。也就是说
//这个事件尚未派发完成,将在下次派发线程的循环中再次尝试派发
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
setInjectionResultLocked(entry, injectionResult);
//如果返回值不为SUCCEEDED,表明无法为事件找到合适的窗口。例如没有窗口处于焦点状态
//或点击的位置没有落在任何一个窗口内,这个事件将被直接丢弃。
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
CancelationOptions::Mode mode(isPointerEvent ?
CancelationOptions::CANCEL_POINTER_EVENTS :
CancelationOptions::CANCEL_NON_POINTER_EVENTS);
CancelationOptions options(mode, "input event injection failed");
synthesizeCancelationEventsForMonitorsLocked(options);
}
return true;
}
//向inputTargets列表中添加特殊的接收目标。可以看出这些名为Monitoring targets的接收
//者可以监听所有的输入事件。
addMonitoringTargetsLocked(inputTargets);
// Dispatch the motion.
//将事件派发给inputTargets列表中的目标
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
//遍历inputTargets
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
//根据InputTarget中的InputChannel获取对应的Connection对象的索引
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
//获取Connection
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
//针对当前的InputTarget启动事件派发循环
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
}
}
}
接下来的代码就不贴了,只要研究了前面几篇,里面的东西只要耐下心看都可以看的懂。