06.输入系统:第10课第10节_输入系统_Dispatcher线程情景分析_dispatch前处理

通过前面几个小节,知道Reader线程从驱动读取到事件之后,还要经过很多的处理才能发送给应用程序,我们来回顾一下,再次粘贴框图如下:
在这里插入图片描述
Reader线程读取事件之后,会把事件稍作处理,然后放入mInboundQueue队列中,然后Dispatcher线程会从这个队列中读取事件,稍作处理之后把这些事件放入到APP应用程序mOutBoundQueue队列之中。然后取出事件发送给对应的APP。

从前面的小节我们知道,Reader线程从驱动读取到事件之后,会调用

getListener()->notifyKey(&args);//通知Dispatcher线程

通知Dispatcher线程,该函数notifyKey位于InputDispatcher.cpp中,首先调用:

mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);

稍作处理,然后无论处理结果如何,调用:

needWake = enqueueInboundEventLocked(newEntry);
if (needWake) {
    mLooper->wake();
}

放入mInbound队列中,然后唤醒Dispatcher线程,Dispatcher线程线程的主题循环(InputDispatcher.cpp中):

bool InputDispatcherThread::threadLoop() {
	mDispatcher->dispatchOnce();
		if (!haveCommandsLocked()) {//如果没有命令
            dispatchOnceInnerLocked(&nextWakeupTime);//生成命令
    	 if (runCommandsLockedInterruptible()) {//运行命令
            nextWakeupTime = LONG_LONG_MIN;

单命令队列为空的时候,会从mInboundQueue取出事件,用它生成命令,然后放入命令队列,或者直接丢弃。,然后通过runCommandsLockedInterruptible()运行命令(对事件稍作处理),最后Dispatcher他。

这是一个大概的流程,下面我们开始阅读代码,下面讲解一个简单例程,不需要把事件常给user。

不传递给user

policyFlags = ~ACTION_PASS_TO_USER;//同时设置标志位,该按键不传递给用户

下面我们找到函数:

bool InputDispatcherThread::threadLoop() {
	if (!haveCommandsLocked()) {
		dispatchOnceInnerLocked(&nextWakeupTime);
 			mPendingEvent = mInboundQueue.dequeueAtHead();//从队列取出事件
 			/*如果这个事件不需要传递给user,则丢弃改事件*/
 			if (dropReason != DROP_REASON_NOT_DROPPED) {
				dropInboundEventLocked(mPendingEvent, dropReason);//丢弃事件		
			case EventEntry::TYPE_KEY: {
			 	done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
					if (done) {
						*nextWakeupTime = LONG_LONG_MIN;  // 处理完之后,继续处理下一个事件

发送给user

无论GlobalKeys,SystemKey都和上述分析一样,只是在dispatchKeyLocked中的处理不一样:

bool InputDispatcherThread::threadLoop() {
	if (!haveCommandsLocked()) {
		dispatchOnceInnerLocked(&nextWakeupTime);
 			mPendingEvent = mInboundQueue.dequeueAtHead();//从队列取出事件
 			/*如果这个事件不需要传递给user,则丢弃改事件*/
 			if (dropReason != DROP_REASON_NOT_DROPPED) {
				dropInboundEventLocked(mPendingEvent, dropReason);//丢弃事件		
			case EventEntry::TYPE_KEY: {
				done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
					/*如果需要拷贝给user*/
					if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) 
						/*构建一个命令*/
				        CommandEntry* commandEntry = postCommandLocked(&InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
				        if (mFocusedWindowHandle != NULL) {
				            commandEntry->inputWindowHandle = mFocusedWindowHandle;
				        }
				        commandEntry->keyEntry = entry;
				        entry->refCount += 1;
				        return false; // wait for the command to run
					Vector<InputTarget> inputTargets;
					/*寻找需要接收的应用程序*/
				    int32_t injectionResult = 
				    findFocusedWindowTargetsLocked(currentTime,entry, inputTargets, nextWakeupTime);
				    ./*发送事件给应用程序*/
				    dispatchEventLocked(currentTime, entry, inputTargets);
 			 runCommandsLockedInterruptible()//执行命令
 			 	CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
 			 	Command command = commandEntry->command;
 			 	/*实际调用前面构造的InputDispatcher::doInterceptKeyBeforeDispatchingLoc方法
 			 	*/
        		(this->*command)(commandEntry);
        			/*调用WindowManagerPolicy.java中的interceptKeyBeforeDispatching
        			根据返回结果设置解析结果*/
				    nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,&event, entry->policyFlags);	
				    mLock.lock();	
				    if (delay < 0) {
				        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
				    } else if (!delay) {
				        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
				    } else {
				        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
				        entry->interceptKeyWakeupTime = now() + delay;
				    }
				
        			 	 		

上面提到会调用WindowManagerPolicy.java中的interceptKeyBeforeDispatching,那么我们查看一下,我们只关心GlobalKeys:

public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) 
	if (isValidGlobalKey(keyCode)&& mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) 
        return -1;

如果为GlobalKeys会返回-1,那么执行:

if (delay < 0) {
    entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;

就会把这个按键忽略,不会传递给user,现在我们来看看mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)函数:

mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)
	/*根据一个Global_Key.xml发送广播给某个组件*/
	context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null);

看了这么多思绪应该比较混乱,下面我们重新总结一些

小节归纳

在这里插入图片描述

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

江南才尽,年少无知!

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

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

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

打赏作者

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

抵扣说明:

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

余额充值