Input系统分析详解-InputDispatcher

本章节仅以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);
        }
    }
}

接下来的代码就不贴了,只要研究了前面几篇,里面的东西只要耐下心看都可以看的懂。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞_哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值