天天看點

06.輸入系統:第10課第13節_輸入系統_Dispatcher線程_分發dispatch

該小節我們講解,Dispatcher線程是如何分發事件的,在這之前,我們先回顧一下之前的學習,下面是一個框圖:

06.輸入系統:第10課第13節_輸入系統_Dispatcher線程_分發dispatch

在前面已經分析過,Dispatcher線程會對資料進行一些處理之後,再分發出去。他首先會把輸入事件分為類(如:Global,System,user等等,對于Global,System處理完之後會直接抛棄,user類會加入隊列,然後分發給應用程式。分發過程一般如下:1.查找目标APP,得到connection。2,把輸入事件放入對應connection的mOutBoundQueue隊列,然後進行分發。

在上小節的視訊中,我們可以知道Dispatcher線程線程中,存在mConnectionsByFd,裡面存在多個connection,每個connection中包括了 inputChannel, inputChannel中又包括了fd1,并且在對應的APP中,存在相應的fd2,這兩個fd來源于

SocketPair,下面是他的主要步驟:

1.查找目标:向WindowManagerService查詢目前視窗,獲得對應的connection。

2.把輸入事件放入connection中的mOutBoundQueue隊列。

3.從隊列中取出事件逐個寫入到檔案句柄中。(這樣,另外一邊的APP就能從對應的fd中讀取事件)

下面我們就根據上述的幾個步驟分析源代碼

源碼分析

在前面的講解中,都是依照按鍵的流程進行分析,已經分析到了InputDispatcher.cpp中的dispatchKeyLocked函數,該函數對輸入事件進行稍微的處理之後,就會進行分發:

InputDispatcher::dispatchKeyLocked()
	injectionResult = findFocusedWindowTargetsLocked(currentTime,entry, inputTargets, nextWakeupTime);//查找目标視窗
	 	if (mFocusedWindowHandle == NULL) {//該變量表示最外面的視窗運作程式,該處不去分析其内部是如何設定
	 		...............................//擷取最外面的視窗
	 	if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {//權限檢查
	 	/*使用mFocusedWindowHandle建構一個InputTarget*/
	 	addWindowTargetLocked(mFocusedWindowHandle,InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,BitSet32(0),inputTargets);
	 		 /*核心:把查詢到的inputChannel指派給 target.inputChannel*/
	 		 target.inputChannel = windowInfo->inputChannel;
	 dispatchEventLocked(currentTime, entry, inputTargets);//發送事件
	 	ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);//擷取fd的索引
	 	/*根據fd的索引提取對應的connection*/
		sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
		prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
			/*把事件(多個)放入隊列*/
			enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
				enqueueDispatchEntryLocked()
					/*把dispatchEntry(某個事件)放入到connection的隊列的尾部*/
					connection->waitQueue.enqueueAtTail(dispatchEntry);
				/*從隊列取出事件,寫入到對應的檔案句柄之中*/
				startDispatchCycleLocked(currentTime, connection);
					/*從隊列頭部取出一個事件*/
					DispatchEntry* dispatchEntry = connection->outboundQueue.head;
						case EventEntry::TYPE_KEY: {//如果為按鍵事件
							connection->inputPublisher.publishKeyEvent()//發送事件
								mChannel->sendMessage(&msg);//建構一個msg,調用該函數發送
									/*寫入到mFd中,對應的應用程式,馬上就能讀取到事件*/
									nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);
           

函數調用到send(),Dispatcher線程基本完成了他的使命,剩下的就是應用程式的事情了。上述函數的詳細調用框圖如下:

06.輸入系統:第10課第13節_輸入系統_Dispatcher線程_分發dispatch

繼續閱讀