本文轉載自:http://blog.csdn.net/u013491946/article/details/72638954
版權聲明:免責聲明: 本人在此發文(包括但不限於漢字、拼音、拉丁字母)均為隨意敲擊鍵盤所出,用於檢驗本人電腦鍵盤錄入、屏幕顯示的機械、光電性能,並不代表本人局部或全部同意、支持或者反對觀點。如需要詳查請直接與鍵盤生產廠商法人代表聯系 .挖井挑水無水表,不會網購無快遞
上一篇Linux/Android——input系統之 kernel層 與 frameworks層交互 (五) 中有介紹kernel層一下以及與Android這邊frameworks層之間的聯系,算是打通android 應用層與 kernel驅動層,對整個input系統的學習是至關重要的,其中frameworks層只是簡單記錄了幾個接入點,這里開始分析frameworks層的細節部分。
撰寫不易,轉載需注明出處:http://blog.csdn.net/jscese/article/details/42392311
input服務的啟動:
android啟動的時候會啟動很多個service,這個可以參考SystemServer.Java ,會啟動InputManagerService這個服務:
- Slog.i(TAG, "Input Manager");
- inputManager = new InputManagerService(context, wmHandler);
- ...
- ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
直接看InputManagerService.java中的start函數:
- public void start() {
- Slog.i(TAG, "Starting input manager");
- nativeStart(mPtr); //調用了本地方法,JNI對應的cpp 在server下的jni目錄下
- ...
- }
這個牽扯到android的server的jni,最開始是在SystemServer中加載android_server這個動態庫,
至於這個動態庫的編譯可參考/frameworks/base/services/jni/Android.mk中的內容
所以在調用這個nativeStart方法時,相關的動態庫已經加載到SystemServer的進程中。
先看下這個start函數在jni文件中的實現,frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp中:
- static void nativeStart(JNIEnv* env, jclass clazz, jint ptr) {
- NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); //這個NativeInputManager 是在上面InputMangerService構造的時候調用nativeInit時new出來的
- status_t result = im->getInputManager()->start(); //這里是調用了NativeInputManager中的InputManager中的start方法,同樣這個InputManager是NativeInputManager構造的時候new出來的
- if (result) {
- jniThrowRuntimeException(env, "Input manager could not be started.");
- }
- }
其實熟悉JNI的話,我分析到這里,就應該差不多了。。對於JNI 不是很了解的話可以參考我之前的博客: Andorid——ubuntu下的 NDK / JNI
看下NativeInputManager構造函數中的:
- sp<EventHub> eventHub = new EventHub();
- mInputManager = new InputManager(eventHub, this, this);
這里的JNI部分就不多說了,現在就看這個InputManager的start方法,上面提到到Android.mk,可以看到include了一個libinput的動態庫,
而這個動態庫的路徑是在/frameworks/base/services/input下,這就明了啦.此目錄下有InputManager.cpp . EventHub.cpp等
直接看start:
- status_t InputManager::start() {
- status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); //這個mDispatcherThread是在InputManager構造函數里調用initialize初始化,這里很明顯啟動了這個名為InputDispatcher的線程
- if (result) {
- ALOGE("Could not start InputDispatcher thread due to error %d.", result);
- return result;
- }
- result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); //同上,開啟線程
- if (result) {
- ALOGE("Could not start InputReader thread due to error %d.", result);
- mDispatcherThread->requestExit();
- return result;
- }
- return OK;
- }
到這里算是看到真面目的感覺,看這兩個線程,字面意思,一個是分發給input事件給當前的activity的,一個是讀取從下層發上來的input事件的
InputDispatcher分發:
從上面的線程啟動分析:
- bool InputDispatcherThread::threadLoop() {
- mDispatcher->dispatchOnce();
- return true;
- }
- 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.
- if (!haveCommandsLocked()) { //如果有緩存的命令就調用下面的runCommand去執行,沒有的話這里去檢查是否有新的input事件,這里定義一個喚醒時間控制
- 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);
- mLooper->pollOnce(timeoutMillis); //執行上面一次分發之后,就進入了loop,這個loop會持續的檢測對應的管道中是否有內容可讀,而另外一個線程InputReader 讀取到input事件之后就會往這個管道寫入
- }
這個是處理input事件的,后續分析,先看怎么讀取事件.
InputReader讀取:
源碼位於frameworks/base/libs/ui/InputReader.cpp ,開啟線程如下:
- bool InputReaderThread::threadLoop() {
- mReader->loopOnce();
- return true;
- }
這里看這個loopOnce:
- void InputReader::loopOnce() {
- ...
- size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); //這里去獲取event事件
- ...
- if (count) {
- processEventsLocked(mEventBuffer, count); //如果獲取到事件,就處理
- }
- ...
- }
可以看到這里就到了獲取event事件了。上一篇中有提到!
getEvent中會一直read,直到get到event之后,通過precessevent處理,最終會喚醒上面介紹到的InputDispatcherThread,通知它有新的事件來了