Linux/Android——Input系統之frameworks層InputManagerService (六)【轉】


本文轉載自: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這個服務:

 

[objc]  view plain  copy
 
 
 
 
  1.    Slog.i(TAG, "Input Manager");  
  2.             inputManager = new InputManagerService(context, wmHandler);  
  3.   
  4. ...  
  5.   
  6.             ServiceManager.addService(Context.INPUT_SERVICE, inputManager);  

直接看InputManagerService.java中的start函數:

[java]  view plain  copy
 
 
 
 
  1.     public void start() {  
  2.         Slog.i(TAG, "Starting input manager");  
  3.         nativeStart(mPtr);   //調用了本地方法,JNI對應的cpp 在server下的jni目錄下  
  4.   
  5. ...  
  6.   
  7. }  

這個牽扯到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中:

 

[objc]  view plain  copy
 
 
 
 
  1. static void nativeStart(JNIEnv* env, jclass clazz, jint ptr) {  
  2.     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);  //這個NativeInputManager 是在上面InputMangerService構造的時候調用nativeInit時new出來的  
  3.   
  4.     status_t result = im->getInputManager()->start(); //這里是調用了NativeInputManager中的InputManager中的start方法,同樣這個InputManager是NativeInputManager構造的時候new出來的  
  5.     if (result) {  
  6.         jniThrowRuntimeException(env, "Input manager could not be started.");  
  7.     }  
  8. }  

其實熟悉JNI的話,我分析到這里,就應該差不多了。。對於JNI 不是很了解的話可以參考我之前的博客: Andorid——ubuntu下的 NDK / JNI 

 

 

看下NativeInputManager構造函數中的:

 

[objc]  view plain  copy
 
 
 
 
  1. sp<EventHub> eventHub = new EventHub();  
  2. mInputManager = new InputManager(eventHub, this, this);  

 

這里的JNI部分就不多說了,現在就看這個InputManager的start方法,上面提到到Android.mk,可以看到include了一個libinput的動態庫,

而這個動態庫的路徑是在/frameworks/base/services/input下,這就明了啦.此目錄下有InputManager.cpp . EventHub.cpp等

直接看start:

[objc]  view plain  copy
 
 
 
 
  1. status_t InputManager::start() {  
  2.     status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);  //這個mDispatcherThread是在InputManager構造函數里調用initialize初始化,這里很明顯啟動了這個名為InputDispatcher的線程  
  3.     if (result) {  
  4.         ALOGE("Could not start InputDispatcher thread due to error %d.", result);  
  5.         return result;  
  6.     }  
  7.   
  8.     result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); //同上,開啟線程  
  9.     if (result) {  
  10.         ALOGE("Could not start InputReader thread due to error %d.", result);  
  11.   
  12.         mDispatcherThread->requestExit();  
  13.         return result;  
  14.     }  
  15.   
  16.     return OK;  
  17. }  

到這里算是看到真面目的感覺,看這兩個線程,字面意思,一個是分發給input事件給當前的activity的,一個是讀取從下層發上來的input事件的

 

 

InputDispatcher分發:

 從上面的線程啟動分析:

 

[objc]  view plain  copy
 
 
 
 
  1. bool InputDispatcherThread::threadLoop() {  
  2.     mDispatcher->dispatchOnce();  
  3.     return true;  
  4. }  
調用分發一次的函數:

 

 

[objc]  view plain  copy
 
 
 
 
  1. void InputDispatcher::dispatchOnce() {  
  2.     nsecs_t nextWakeupTime = LONG_LONG_MAX;  
  3.     { // acquire lock  
  4.         AutoMutex _l(mLock);  
  5.         mDispatcherIsAliveCondition.broadcast();  
  6.   
  7.         // Run a dispatch loop if there are no pending commands.  
  8.         // The dispatch loop might enqueue commands to run afterwards.  
  9.         if (!haveCommandsLocked()) {           //如果有緩存的命令就調用下面的runCommand去執行,沒有的話這里去檢查是否有新的input事件,這里定義一個喚醒時間控制  
  10.             dispatchOnceInnerLocked(&nextWakeupTime);  
  11.         }  
  12.   
  13.         // Run all pending commands if there are any.  
  14.         // If any commands were run then force the next poll to wake up immediately.  
  15.         if (runCommandsLockedInterruptible()) {  
  16.             nextWakeupTime = LONG_LONG_MIN;  
  17.         }  
  18.     } // release lock  
  19.   
  20.     // Wait for callback or timeout or wake.  (make sure we round up, not down)  
  21.     nsecs_t currentTime = now();  
  22.     int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);  
  23.     mLooper->pollOnce(timeoutMillis);  //執行上面一次分發之后,就進入了loop,這個loop會持續的檢測對應的管道中是否有內容可讀,而另外一個線程InputReader 讀取到input事件之后就會往這個管道寫入  
  24. }  

這個是處理input事件的,后續分析,先看怎么讀取事件.

 

 

 

InputReader讀取:

  源碼位於frameworks/base/libs/ui/InputReader.cpp ,開啟線程如下:

 

[objc]  view plain  copy
 
 
 
 
  1. bool InputReaderThread::threadLoop() {  
  2.     mReader->loopOnce();  
  3.     return true;  
  4. }  

這里看這個loopOnce:

 

[objc]  view plain  copy
 
 
 
 
  1. void InputReader::loopOnce() {  
  2.   
  3. ...  
  4.   
  5.    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);  //這里去獲取event事件  
  6.   
  7. ...  
  8.   
  9.         if (count) {  
  10.             processEventsLocked(mEventBuffer, count); //如果獲取到事件,就處理  
  11.         }  
  12.   
  13. ...  
  14.   
  15. }  

可以看到這里就到了獲取event事件了。上一篇中有提到!

getEvent中會一直read,直到get到event之后,通過precessevent處理,最終會喚醒上面介紹到的InputDispatcherThread,通知它有新的事件來了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM