本文基於Android-4.0 原文:http://www.cnblogs.com/lcw/p/3374466.htmlhtml
請看:www.cnblogs.com/lcw/p/3373214.htmlnode
在理論中談到EventHub,這個一看就是一個作實事的,確定不是領導,哪它的領導是誰呢?android
從如下幾方面來分析此問題:數據結構
先看一下每一個模塊的工做職責:EventHub, InputReader, InputManager...app
它是系統中全部事件的中央處理站。它管理全部系統中能夠識別的輸入設備的輸入事件,此外,當設備增長或刪除時,EventHub將產生相應的輸入事件給系統。異步
EventHub經過getEvents函數,給系統提供一個輸入事件流。它也支持查詢輸入設備當前的狀態(如哪些鍵當前被按下)。並且EventHub還跟蹤每一個輸入調入的能力,好比輸入設備的類別,輸入設備支持哪些按鍵。 函數
InputReader從EventHub中讀取原始事件數據(RawEvent),並由各個InputMapper處理以後輸入對應的input listener.oop
InputReader擁有一個InputMapper集合。它作的大部分工做在InputReader線程中完成,可是InputReader能夠接受任意線程的查詢。爲了可管理性,InputReader使用一個簡單的Mutex來保護它的狀態。this
InputReader擁有一個EventHub對象,但這個對象不是它建立的,而是在建立InputReader時做爲參數傳入的。spa
InputDispatcher負責把事件分發給輸入目標,其中的一些功能(如識別輸入目標)由獨立的policy對象控制。
InputManager是系統事件處理的核心,它雖然不作具體的事,但管理工做仍是要作的,好比接受咱們客戶的投訴和索賠要求,或者老闆的出所筒。
InputManager使用兩個線程:
InputReaderThread類與InputDispatcherThread類不共享內部狀態,全部的通訊都是單向的,從InputReaderThread到InputDispatcherThread。兩個類能夠經過InputDispatchPolicy進行交互。
InputManager類從不與Java交互,而InputDispatchPolicy負責執行全部與系統的外部交互,包括調用DVM業務。
result = gNativeInputManager->getInputManager()->start();
result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
在上面的Thread::run中,調用createThreadEtc函數,並以Thread::_threadLoop做爲入口函數,以上面的mDispatcherThread或mReaderThread做爲userdata建立線程。
至此InputReader線程和InputDispatcher線程都已經工做,詳細信息見Thread::_threadLoop,在此函數中它將調用mDispatcherThread或mReaderThread的threadLoop函數來作真正的事。
bool InputReaderThread::threadLoop() { mReader->loopOnce(); return true; }
bool InputDispatcherThread::threadLoop() { mDispatcher->dispatchOnce(); return true; }
從EventHub::getEvents讀取的事件數據結構以下:
讀取事件時的調用流程爲:
Thread::_threadLoop-> InputReaderThread::threadLoop-> InputReader::loopOnce-> EventHub::getEvents->
在EventHub::getEvents中,當mNeedToScanDevices爲true時<當建立EventHub對象時,它就爲true>,它將從/dev/input目錄下查找全部設備,並進行打開,獲取其相關屬性,最後加入mDevices列表中。
EventHub::scanDevicesLocked->
EventHub::scanDirLocked("/dev/input")->
EventHub::openDeviceLocked
打開事件輸入設備,在用戶態調用open,則在kernel態中調用evdev_open函數,evdev_open處理流程以下:
要說EventHub::getEvents如何獲取輸入事件,不得不先說說它的幾個相關的成員變量:
注:epoll_event只代表某個設備上有事件,並不包含事件內容,具體事件內容須要經過read來讀取。
在調用epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis)以後,讀到的epoll_event事件保存在mPendingEventItems,總共的事件數保存在mPendingEventCount,固然,在調用epoll_event以前,mPendingEventIndex被清0,直正的事件處理在下面的代碼中。
epoll_wait只是告訴咱們Device已經有事件了,讓咱們去讀,真正讀取設備輸入事件的代碼如上,其流程以下:
read(device->fd, readBuffer, sizeof(struct input_event) * capacity);這些input_event是由各個註冊的input_device報告給input子系統的。
至此,事件已經讀取到用戶態,如今看看EventHub怎麼處理這些事件?
首先經過epoll_wait查看哪些設備有事件,而後經過read從有事件的設備中讀取事件,如今事件已經讀取到用戶態,且數據結構爲input_event,保存在EventHub::getEvents的readBuffer中。
下面就看看這些事件下一步的東家是誰?
1)首先把input_event的信息填入RawEvent中,其相關代碼以下:
2)若是是input_event的類型爲EV_KEY,則須要調用device->keyMap.keyLayoutMap->mapKey函數把iput_event.code映射爲RawEvent.keyCode。
相關數據結構關係以下圖所示:
至此,EventHub::getEvents讀取事件的任務已經完成。
下面看看RawEvent的命運如何呢?
先溫習一下讀取事件時的調用流程爲:
Thread::_threadLoop->
InputReaderThread::threadLoop->
InputReader::loopOnce->
EventHub::getEvents->
在InputReader::loopOnce中,當調用EventHub->getEvents獲取到RawEvent以後,調用InputReader::processEventsLocked來處理這些事件,而後調用mQueuedListener->flush()把這些隊列中的事件發送到Listener。
在InputReader::processEventsLocked主要分兩步處理:
增長事件的流程爲:爲一個新增的Device建立一個InputDevice,並增長到InputReader::mDevices中;根據新增長設備的class類別,建立對應的消息轉換器(InputMapper),而後此消息轉換器加入InputDevice::mMappers中。消息轉換器負責把讀取的RawEvent轉換成特定的事件,以供應用程序使用。
InputMapper關係以下圖所示
- EventHub管理一堆Device,每個Device與Kernel中一個事件輸入設備對應
- InputReader管理一堆InputDevice,每個InputDevice與EventHub中的Device對應
- InputDevice管理一些與之相關的InputMapper,每個InputMapper與一個特定的應用事件相對應,如:SingleTouchInputMapper。
processEventsLocked已經把來自於事件設備的事件煮熟以後放入到各類NotifyArgs(如NotifyMotionArgs)之中,而後把這些各類NotifyArgs加入InputReader::mQueuedListener::mArgsQueue鏈表中。本Flush函數就是要把mArgsQueue中的全部NotifyArgs進行處理。
調用鏈表中每一個NotifyArgs的notify函數,且有一個有意思的參數 mInnerListener,這個參數在前面屢次提到過,它是在建立mQueuedListener時提供的,它其實就是InputManager中的mDispatcher,前面一直在InputReader中打轉轉,如今終於看到InputDispatcher登場了,說明事件很快就能夠謝幕了。
再向下看一下,這麼多類NotifyArgs,爲描述方便,以NotifyMotionArgs爲例,其代碼爲:
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const { listener->notifyMotion(this); }
下面就看看InputDispatcher(mDispatcher)的notifyMotion函數作了些什麼。
這個InputDispatcher::notifyMotion(const NotifyMotionArgs* args)可就不簡單了。
在InputDispatcher::notifyMotion中:
- 根據NotifyMotionArgs提供的信息,構造一個MotionEvent,再調用mPolicy->filterInputEvent看是否須要丟棄此事件,若是須要丟棄則立刻返加。其中mPolicy爲NativeInputManager實例,在構造InputDispatcher時提供的參數。
- 對於AMOTION_EVENT_ACTION_UP或AMOTION_EVENT_ACTION_DOWN事件,則直接根據NotifyMotionArgs提供的信息,構造一個MotionEntry。
- 調用InputDispatcher::enqueueInboundEventLocked把新構造的MotionEntry添加到InputDispatcher::mInboundQueue中,並返回是否須要喚醒mLooper<向pipe中寫入數據>的標識。
以上操做都是在InputReader線程中完成的,如今應該InputDispatcher線程開始工做了。
InputDispatcherThread主循環以下:
Thread::_threadLoop->
InputDispatcherThread::threadLoop->
mDispatcher->dispatchOnce(InputDispatcher::dispatchOnce)->
dispatchOnceInnerLocked then
mLooper->pollOnce
先看看簡單的mLooper->pollOnce
其功能爲等待超時或被pipe喚醒(InputReader線程調用InputDispatcher::notifyMotion時, InputDispatcher::notifyMotion根據狀況調用mLooper->wake)。
其調用流程以下:
mLooper->pollOnce(int timeoutMillis)->
Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData)->
- 從mInboundQueue從中依次取出EventEntry<MotionEntry的基類>,
- 調用InputDispatcher::dispatchMotionLocked處理此MotionEntry
- 調用InputDispatcher::dispatchEventToCurrentInputTargetsLocked
對於InputDispatcher::mCurrentInputTargets中的每個InputTarget,並獲取對應的Connection,調用InputDispatcher::prepareDispatchCycleLocked,
其相關代碼以下:
至此,整個Android事件處理系統就介紹完了。
下面是我作"電視棒遠程萬能遙控器"項目時寫的分析,只列出了關鍵步驟