InputManagerService之事件的初始化與分發

該篇文章接總章,來詳細談論說明InputManagerService 體系,從初始化到事件獲取跟分發。咱們在進行前,先明確哪幾個問題需要知道,然後看看在這篇文章中是否解決了這些問題。對於InputManagerService,大家第一個想知道是他起什麼作用,這個在總章裏面有詳細說明,簡而言之就是獲得事件跟分發處理事件。那他如何或者跟其他模塊配合獲取事件?並且把這個事件進行分發?如何準確定位對應的處理事件的模塊?咱們下面開始討論這些問題,在這個文章出來的時候,android 已經到N了 ,也就是7.0。但是由於我的筆記(初稿) 在M的時候已經完成了,也就是去年。所以這篇文章還是基於M (6.0)來寫。

        InputManagerService的初始化:

        跟其他模塊一樣,作爲系統的核心服務初始化在SystemServer。基本系統的核心服務都是在這裏初始化,這個可以研究下系統的啓動流程,在啓動的最後就是需要啓動所有的核心服務。

       代碼路徑:    frameworks/base/services/java/com/android/server/SystemServer.java   

       在run 方法裏面,M 是在startOtherService()裏面初始化InputManagerService

      

         上面主要是新建IMS(InputManagerService 下面都用這個替換) 對象, 然後把WindowManagerService的InputMonitor作爲參數傳給IMS,重點關注下InputMonitor,這個跟事件的分發有關。然後在這裏調用start方法啓動IMS,這裏的start 實際是調用 native 的start 方法。

         看下InputManagerServices的start方法:

         代碼路徑:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

       

上面主要調用了com_android_service_input_InputManagerService.cpp 裏面的nativeStart方法,Java層的start方法主要做了兩個工作:一個工作就是調用nativeStart方法。另外一個就是point 跟 toucher 相關參數設置跟監聽,對應這Input事件的主要兩類:Key 跟 toucher。在nativeStart裏面的mPtr對應啥呢?首先Java層 跟 native層通信調用,主要通過JNI。這裏主要是mPtr指針強制類型轉換爲NativeInputManager對象,看下源碼:

Java層代碼:

代碼路徑:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

  1.     // Pointer to native input manager service object.  
  2.     private final long mPtr;  
  3. public InputManagerService(Context context) {  
  4.         this.mContext = context;  
  5.         this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());  
  6. <span style="white-space:pre;"> </span>mUseDevInputEventForAudioJack =  
  7.                 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);  
  8.         Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="  
  9.                 + mUseDevInputEventForAudioJack);  
  10. <span style="white-space:pre;"> </span>//這裏對mPtr 進行初始化,調用的還是native的方法,把這個service跟 Systemcontext 傳給native對應的方法  
  11.         mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());  
  12. <span style="white-space:pre;"> </span> LocalServices.addService(InputManagerInternal.classnew LocalService());  
  13.     }  
    // Pointer to native input manager service object.
    private final long mPtr;
public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
	mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
	//這裏對mPtr 進行初始化,調用的還是native的方法,把這個service跟 Systemcontext 傳給native對應的方法
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
	 LocalServices.addService(InputManagerInternal.class, new LocalService());
    }
Native層代碼:

  代碼路徑:/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

  1. static jlong nativeInit(JNIEnv* env, jclass /* clazz */,  
  2.     jobject serviceObj, jobject contextObj, jobject messageQueueObj) {  
  3. sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);  
  4. if (messageQueue == NULL) {  
  5.     jniThrowRuntimeException(env, "MessageQueue is not initialized.");  
  6.     return 0;  
  7. }   //這裏把JAVA層的  Systemcontext 以及IMS自己 作爲參數傳過來了  
  8. an style="white-space:pre;">    </span>NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,  
  9.         messageQueue->getLooper());  
  10. im->incStrong(0);  
  11. return reinterpret_cast<jlong>(im);  
    static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }   //這裏把JAVA層的  Systemcontext 以及IMS自己 作爲參數傳過來了
 	NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
   }
這個爲什麼要把IMS 傳給NativeInputManager呢?看下NativeInputManager的構造函數

代碼路徑:frameworks/base/services/core/jni/com_android_server_input_inputmanagerservice.cpp

  1. NativeInputManager::NativeInputManager(jobject contextObj,  
  2.         jobject serviceObj, const sp<Looper>& looper) :  
  3.         mLooper(looper), mInteractive(true) {  
  4.     JNIEnv* env = jniEnv();  
  5.   
  6.     mContextObj = env->NewGlobalRef(contextObj);  
  7.     mServiceObj = env->NewGlobalRef(serviceObj);  
  8.    {  
  9.         AutoMutex _l(mLock);  
  10.         mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;  
  11.         mLocked.pointerSpeed = 0;  
  12.         mLocked.pointerGesturesEnabled = true;  
  13.         mLocked.showTouches = false;  
  14.     }  
  15. <span style="white-space:pre;"> </span>mInteractive = true;  
  16. <span style="white-space:pre;"> </span>//這個是從底層讀取input 信息的提供者  
  17.      sp<EventHub> eventHub = new EventHub();  
  18.     mInputManager = new InputManager(eventHub, thisthis);  
  19. }  
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();

    mContextObj = env->NewGlobalRef(contextObj);
    mServiceObj = env->NewGlobalRef(serviceObj);
   {
        AutoMutex _l(mLock);
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
    }
	mInteractive = true;
	//這個是從底層讀取input 信息的提供者
     sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}
這裏有一個重要的對象就是EventHub,如總章所說這個對象是事件獲取的重要的對象。在這裏也對Native層的InputManager進行了初始化。前面解決了mPtr 是啥,nativeStart又幹了啥?

InputManagerService的讀取跟分發啓動:

  1. static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {  
  2.     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);  
  3.     //這裏就是上面獲得InputManager對象調用start()方法返回的結果  
  4.     status_t result = im->getInputManager()->start();  
  5.     if (result) {  
  6.         jniThrowRuntimeException(env, "Input manager could not be started.");  
  7.     }  
  8. }  
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    //這裏就是上面獲得InputManager對象調用start()方法返回的結果
    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}
查看下InputManager的start方法到底幹了什麼?frameworks/native/services/inputFlinger/InputManager.cpp

代碼路徑:frameworks/native/services/inputFlinger/InputManager.cpp

  1. status_t InputManager::start() {  
  2.     status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);  
  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. }  
status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    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 事件 消息讀取分發的工作啓動了,從上面的代碼就可以知道這裏開啓了兩個線程,這兩個線程初始化在InputManager的initialize方法裏面。

  1. void InputManager::initialize() {  
  2.     mReaderThread = new InputReaderThread(mReader);  
  3.     mDispatcherThread = new InputDispatcherThread(mDispatcher);  
  4. }  
void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
這兩個線程主要一個是讀取事件,一個是分發事件。讀取事件從哪裏讀呢?從EventHub裏面讀,源碼說了~

代碼路徑:frameworks/native/services/inputflinger/InputReader.h

  1. /* Reads raw events from the event hub and processes them, endlessly. */   這裏說明了  
  2. class InputReaderThread : public Thread {  
  3. public:  
  4.     InputReaderThread(const sp<InputReaderInterface>& reader);  
  5.     virtual ~InputReaderThread();  
  6.   
  7. private:  
  8.     sp<InputReaderInterface> mReader;  
  9.   
  10.     virtual bool threadLoop();  
  11. };  
/* Reads raw events from the event hub and processes them, endlessly. */   這裏說明了
class InputReaderThread : public Thread {
public:
    InputReaderThread(const sp<InputReaderInterface>& reader);
    virtual ~InputReaderThread();

private:
    sp<InputReaderInterface> mReader;

    virtual bool threadLoop();
};
那這個線程如何讀取數據呢?
代碼路徑:frameworks/native/services/inputflinger/InputReader.cpp

  1. // --- InputReaderThread ---  
  2. InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :  
  3.          Thread(/*canCallJava*/ true), mReader(reader) {  
  4. }  
  5. InputReaderThread::~InputReaderThread() {  
  6. }  
  7. bool InputReaderThread::threadLoop() {  
  // --- InputReaderThread ---
  InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
           Thread(/*canCallJava*/ true), mReader(reader) {
  }
  InputReaderThread::~InputReaderThread() {
  }
  bool InputReaderThread::threadLoop() {
  1. //調用loopOnce 方法      
  2. mReader->loopOnce();  
  3.   return true;  
     //調用loopOnce 方法    
     mReader->loopOnce();
       return true;
  }
InputReader 實際不直接訪問設備點,而是通過EventHub 來完成這一工作,EventHub 通過讀取/dev/input下的數據。loopOnce如何讀取事件了,前面已經反覆強調讀取數據的工作主要是EventHub,那loopOnce裏面EventHub就要一定要出現了。

  1. void InputReader::loopOnce() {  
  2.     int32_t oldGeneration;  
  3.     int32_t timeoutMillis;  
  4.     bool inputDevicesChanged = false;  
  5.     Vector<InputDeviceInfo> inputDevices;  
  6. //這裏主要是 環境有關的,比如時間,比如設備的狀態等等  
  7.     { // acquire lock  
  8.        AutoMutex _l(mLock);  
  9.   
  10.         oldGeneration = mGeneration;  
  11.         timeoutMillis = -1;  
  12.   
  13.         uint32_t changes = mConfigurationChangesToRefresh;  
  14.          if (changes) {  
  15.             mConfigurationChangesToRefresh = 0;  
  16.             timeoutMillis = 0;  
  17.             //主要刷新環境  
  18.             refreshConfigurationLocked(changes);  
  19.         } else if (mNextTimeout != LLONG_MAX) {  
  20.             nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);  
  21.             timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);  
  22.         }  
  23.     } // release lock  
  24.    //獲得input 數據  
  25.     size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);  
  26.     //這裏主要處理消息設備  
  27.     { // acquire lock  
  28.         AutoMutex _l(mLock);  
  29.         mReaderIsAliveCondition.broadcast();  
  30.   
  31.         if (count) {  
  32.             //這裏主要是 添加事情的設備  
  33.             processEventsLocked(mEventBuffer, count);  
  34.         }  
  35.         if (mNextTimeout != LLONG_MAX) {  
  36.             nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);  
  37.             if (now >= mNextTimeout) {  
  38. #if DEBUG_RAW_EVENTS  
  39.                 ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);  
  40. #endif  
  41.                 mNextTimeout = LLONG_MAX;  
  42.                 timeoutExpiredLocked(now);  
  43.             }  
  44.         }  
  45.     if (oldGeneration != mGeneration) {  
  46.             inputDevicesChanged = true;  
  47.             getInputDevicesLocked(inputDevices);  
  48.         }  
  49.     } // release lock  
  50.  // Send out a message that the describes the changed input devices.  
  51.     if (inputDevicesChanged) {  
  52.         mPolicy->notifyInputDevicesChanged(inputDevices);  
  53.     }  
  54.     // Flush queued events out to the listener.  
  55.     // This must happen outside of the lock because the listener could potentially call  
  56.     // back into the InputReader's methods, such as getScanCodeState, or become blocked  
  57.     // on another thread similarly waiting to acquire the InputReader lock thereby  
  58.     // resulting in a deadlock.  This situation is actually quite plausible because the  
  59.     // listener is actually the input dispatcher, which calls into the window manager,  
  60.     // which occasionally calls into the input reader.  
void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector<InputDeviceInfo> inputDevices;
//這裏主要是 環境有關的,比如時間,比如設備的狀態等等
    { // acquire lock
       AutoMutex _l(mLock);

        oldGeneration = mGeneration;
        timeoutMillis = -1;

        uint32_t changes = mConfigurationChangesToRefresh;
         if (changes) {
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0;
            //主要刷新環境
            refreshConfigurationLocked(changes);
        } else if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } // release lock
   //獲得input 數據
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    //這裏主要處理消息設備
    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();

        if (count) {
            //這裏主要是 添加事情的設備
            processEventsLocked(mEventBuffer, count);
        }
        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
                mNextTimeout = LLONG_MAX;
                timeoutExpiredLocked(now);
            }
        }
 	if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);
        }
    } // release lock
 // Send out a message that the describes the changed input devices.
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }
    // Flush queued events out to the listener.
    // This must happen outside of the lock because the listener could potentially call
    // back into the InputReader's methods, such as getScanCodeState, or become blocked
    // on another thread similarly waiting to acquire the InputReader lock thereby
    // resulting in a deadlock.  This situation is actually quite plausible because the
    // listener is actually the input dispatcher, which calls into the window manager,
    // which occasionally calls into the input reader.
  1.     //獲得數據後,刷新數據,mQueueListener,根據構造函數以及註釋可以知道是InputDispatcher的一個封裝  
  2.     //查看InputReader的構造函數, InputDispatcher 轉成了這個  
  3.     //這裏主要是刷新消息棧,進行事件的分發了  
  4.     //QueuedInputListener  定義在 InputListener.cpp裏面  
  5.    mQueuedListener->flush();  
  6. }  
    //獲得數據後,刷新數據,mQueueListener,根據構造函數以及註釋可以知道是InputDispatcher的一個封裝
    //查看InputReader的構造函數, InputDispatcher 轉成了這個
    //這裏主要是刷新消息棧,進行事件的分發了
    //QueuedInputListener  定義在 InputListener.cpp裏面
   mQueuedListener->flush();
}
看下loopOnce方法EventHub果然出現了,在這個幾十行代碼裏面讀取事件EventHub,flush 分發事件都有了,基本上就走完了Input事件的讀取跟分發。現在準備進入事件分發的解讀,事件的讀取由於涉及到kernel層代碼的解讀,作爲子章進行分析說明,本篇不做過多解讀。這裏從mQueuedListener->flush(); 開始說明。

代碼路徑:frameworks/native/services/inputflinger/InputListener.cpp

  1. void QueuedInputListener::flush() {  
  2.     size_t count = mArgsQueue.size();  
  3.     for (size_t i = 0; i < count; i++) {  
  4.         NotifyArgs* args = mArgsQueue[i];  
  5.         args->notify(mInnerListener);  
  6.         delete args;  
  7.     }  
  8.     mArgsQueue.clear();  
  9. }  
   void QueuedInputListener::flush() {
       size_t count = mArgsQueue.size();
       for (size_t i = 0; i < count; i++) {
           NotifyArgs* args = mArgsQueue[i];
           args->notify(mInnerListener);
           delete args;
       }
       mArgsQueue.clear();
   }
代碼路徑:frameworks/native/services/inputflinger/inputListener.h

  1. /* 
  2.  * An implementation of the listener interface that queues up and defers dispatch 
  3.  * of decoded events until flushed. 
  4.  */  
  5. class QueuedInputListener : public InputListenerInterface {  
  6. protected:  
  7.     virtual ~QueuedInputListener();  
  8. public:  
  9.     QueuedInputListener(const sp<InputListenerInterface>& innerListener);  
  10.     virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);  
  11.     virtual void notifyKey(const NotifyKeyArgs* args);  
  12.     virtual void notifyMotion(const NotifyMotionArgs* args);  
  13.     virtual void notifySwitch(const NotifySwitchArgs* args);  
  14.     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);  
  15.     void flush();  
  16. private:  
  17.     sp<InputListenerInterface> mInnerListener;  
  18.     Vector<NotifyArgs*> mArgsQueue;  
  19. };  
  20. /* 
  21.  * The interface used by the InputReader to notify the InputListener about input events. 
  22.  */  
  23. class InputListenerInterface : public virtual RefBase {  
  24. protected:  
  25.     InputListenerInterface() { }  
  26.     virtual ~InputListenerInterface() { }  
  27. public:  
  28.     virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;  
  29.     virtual void notifyKey(const NotifyKeyArgs* args) = 0;  
  30.     virtual void notifyMotion(const NotifyMotionArgs* args) = 0;  
  31.     virtual void notifySwitch(const NotifySwitchArgs* args) = 0;  
  32.     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;  
  33. };  
   /*
    * An implementation of the listener interface that queues up and defers dispatch
    * of decoded events until flushed.
    */
   class QueuedInputListener : public InputListenerInterface {
   protected:
       virtual ~QueuedInputListener();
   public:
       QueuedInputListener(const sp<InputListenerInterface>& innerListener);
       virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
       virtual void notifyKey(const NotifyKeyArgs* args);
       virtual void notifyMotion(const NotifyMotionArgs* args);
       virtual void notifySwitch(const NotifySwitchArgs* args);
       virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
       void flush();
   private:
       sp<InputListenerInterface> mInnerListener;
       Vector<NotifyArgs*> mArgsQueue;
   };
   /*
    * The interface used by the InputReader to notify the InputListener about input events.
    */
   class InputListenerInterface : public virtual RefBase {
   protected:
       InputListenerInterface() { }
       virtual ~InputListenerInterface() { }
   public:
       virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;
       virtual void notifyKey(const NotifyKeyArgs* args) = 0;
       virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
       virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
       virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
   };
由上可知繼承inputListenerInterface的子類,會根據情況處理相應的事件。在這裏有一個問題InputDispatcher 如何被強轉的?其實是InputReader在初始化的時候InputDispatcher作爲參數傳了過去,然後強轉了。上代碼說明下:

  1. InputManager::InputManager(  
  2.         const sp<EventHubInterface>& eventHub,  
  3.         const sp<InputReaderPolicyInterface>& readerPolicy,  
  4.         const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {  
  5.     mDispatcher = new InputDispatcher(dispatcherPolicy);  
  6.     mReader = new InputReader(eventHub, readerPolicy, mDispatcher);  
  7.     initialize();  
  8. }  
  9.   
  10. // --- InputReader ---  
  11. InputReader::InputReader(const sp<EventHubInterface>& eventHub,  
  12.         const sp<InputReaderPolicyInterface>& policy,  
  13.        //結合上面的代碼 以及 這句代碼可以知道inputdispatcher被強轉了,爲什麼可以強轉?  
  14.        //因爲inputListenerInterface這個接口繼承Refbase,Refbase是android裏面的所有對象的父類  
  15.        //詳情參考binder裏面的介紹  
  16.         const sp<InputListenerInterface>& listener) :  
  17.         mContext(this), mEventHub(eventHub), mPolicy(policy),  
  18.         mGlobalMetaState(0), mGeneration(1),  
  19.         mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),  
  20.         mConfigurationChangesToRefresh(0) {  
   InputManager::InputManager(
           const sp<EventHubInterface>& eventHub,
           const sp<InputReaderPolicyInterface>& readerPolicy,
           const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
       mDispatcher = new InputDispatcher(dispatcherPolicy);
       mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
       initialize();
   }

   // --- InputReader ---
   InputReader::InputReader(const sp<EventHubInterface>& eventHub,
           const sp<InputReaderPolicyInterface>& policy,
          //結合上面的代碼 以及 這句代碼可以知道inputdispatcher被強轉了,爲什麼可以強轉?
          //因爲inputListenerInterface這個接口繼承Refbase,Refbase是android裏面的所有對象的父類
          //詳情參考binder裏面的介紹
           const sp<InputListenerInterface>& listener) :
           mContext(this), mEventHub(eventHub), mPolicy(policy),
           mGlobalMetaState(0), mGeneration(1),
           mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
           mConfigurationChangesToRefresh(0) {
把InputDispatcher強轉說清楚,咱們就開始詳細瞭解下事情的分發過程,咱們從notifykey這方法說起

  1.      代碼路徑:frameworks/native/services/inputflinger/InputDispatcher.cpp  
  2.   void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {  
  3.       Code 省略,前面主要檢查這個事件有沒有問題,把事件裏面的信息屬性都抽出來,重點看下面的代碼  
  4.       bool needWake;  
  5.       { // acquire lock  
  6.         mLock.lock();  
  7.   
  8.   
  9.         if (shouldSendKeyToInputFilterLocked(args)) {  
  10.             mLock.unlock();  
  11.   
  12.   
  13.             policyFlags |= POLICY_FLAG_FILTERED;  
  14.             if (!mPolicy->filterInputEvent(&event, policyFlags)) {  
  15.                 return// event was consumed by the filter  
  16.             }  
  17.   
  18.   
  19.             mLock.lock();  
  20.         }  
  21.   
  22.   
  23.         int32_t repeatCount = 0;  
  24.         KeyEntry* newEntry = new KeyEntry(args->eventTime,  
  25.                 args->deviceId, args->source, policyFlags,  
  26.                 args->action, flags, keyCode, args->scanCode,  
  27.                 metaState, repeatCount, args->downTime);  
  28.   
  29.   
  30.         needWake = enqueueInboundEventLocked(newEntry);  
  31.         mLock.unlock();  
  32.     } // release lock  
     代碼路徑:frameworks/native/services/inputflinger/InputDispatcher.cpp
  void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
      Code 省略,前面主要檢查這個事件有沒有問題,把事件裏面的信息屬性都抽出來,重點看下面的代碼
      bool needWake;
      { // acquire lock
        mLock.lock();


        if (shouldSendKeyToInputFilterLocked(args)) {
            mLock.unlock();


            policyFlags |= POLICY_FLAG_FILTERED;
            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
                return; // event was consumed by the filter
            }


            mLock.lock();
        }


        int32_t repeatCount = 0;
        KeyEntry* newEntry = new KeyEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, flags, keyCode, args->scanCode,
                metaState, repeatCount, args->downTime);


        needWake = enqueueInboundEventLocked(newEntry);
        mLock.unlock();
    } // release lock
  1. if (needWake) {  
    if (needWake) {
  1.         //事件分發主要在這裏,但是要分發要看needWake的值,<span style="color:rgb(72,72,76);font-size:13px;line-height:1.38462;white-space:pre-wrap;background-color:rgb(247,247,249);">enqueueInboundEventLocked 返回true,事件就開始分發了</span>  
  2.         mLooper->wake();  
  3.     }  
  4.   }  
        //事件分發主要在這裏,但是要分發要看needWake的值,enqueueInboundEventLocked 返回true,事件就開始分發了
        mLooper->wake();
    }
  }

       這裏looper 什麼怎麼進行分發呢?還是看源碼

  1. // --- InputDispatcherThread ---    這個主要在InputDispatcher.cpp裏面  
  2.  InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :  
  3.            Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {  
  4.   }  
  5.    InputDispatcherThread::~InputDispatcherThread() {  
  6.    }  
  7.   . bool InputDispatcherThread::threadLoop() {  
  8.        //開始調用dispatchOnce方法  
  9.        mDispatcher->dispatchOnce();  
  10.        return true;  
  11.  . }  
  12.   . } // namespace android  
// --- InputDispatcherThread ---    這個主要在InputDispatcher.cpp裏面
 InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
           Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
  }
   InputDispatcherThread::~InputDispatcherThread() {
   }
  . bool InputDispatcherThread::threadLoop() {
       //開始調用dispatchOnce方法
       mDispatcher->dispatchOnce();
       return true;
 . }
  . } // namespace android
  1. void InputDispatcher::dispatchOnce() {  
  2.     nsecs_t nextWakeupTime = LONG_LONG_MAX;  
  3.     { // acquire lock  
  4.         AutoMutex _l(mLock);  
  5.         mDispatcherIsAliveCondition.broadcast();  
  6.         // Run a dispatch loop if there are no pending commands.  
  7.         // The dispatch loop might enqueue commands to run afterwards.  
  8.         if (!haveCommandsLocked()) {  
  9.             //調用下面的方法  
  10.             dispatchOnceInnerLocked(&nextWakeupTime);  
  11.         }  
   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()) {
               //調用下面的方法
               dispatchOnceInnerLocked(&nextWakeupTime);
           }
         到這裏就開始說明分發事件了,TouchEvent的消息分發結構來分析Input 在Framework的使用

  1. Code In InputDispatcher.cpp 裏面  
  2. void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {  
  3. Code  省略  
  4. case EventEntry::TYPE_MOTION: {  
  5.         MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);  
  6.         if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {  
  7.             dropReason = DROP_REASON_APP_SWITCH;  
  8.         }  
  9.         if (dropReason == DROP_REASON_NOT_DROPPED  
  10.                 && isStaleEventLocked(currentTime, typedEntry)) {  
  11.             dropReason = DROP_REASON_STALE;  
  12.         }  
  13.         if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {  
  14.             dropReason = DROP_REASON_BLOCKED;  
  15.         }  
  16.         //跳轉到下面個函數,去處理motion相關操作  
  17.         done = dispatchMotionLocked(currentTime, typedEntry,  
  18.                 &dropReason, nextWakeupTime);  
  19.         break;  
  20.     }  
   Code In InputDispatcher.cpp 裏面
   void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
   Code  省略
   case EventEntry::TYPE_MOTION: {
           MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
           if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
               dropReason = DROP_REASON_APP_SWITCH;
           }
           if (dropReason == DROP_REASON_NOT_DROPPED
                   && isStaleEventLocked(currentTime, typedEntry)) {
               dropReason = DROP_REASON_STALE;
           }
           if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
               dropReason = DROP_REASON_BLOCKED;
           }
           //跳轉到下面個函數,去處理motion相關操作
           done = dispatchMotionLocked(currentTime, typedEntry,
                   &dropReason, nextWakeupTime);
           break;
       }
 
  1. bool InputDispatcher::dispatchMotionLocked(  
  2.         nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {  
  3.     //進行motion事件,進行處理  
  4.     // Preprocessing.  
  5.     if (! entry->dispatchInProgress) {  
  6.         entry->dispatchInProgress = true;  
  7.         //這個函數把motion的相關值打出來  
  8.         logOutboundMotionDetailsLocked("dispatchMotion - ", entry);  
  9.     }  
  10.  // Clean up if dropping the event.  
  11. 把舊有的數據清楚掉  
  12.     if (*dropReason != DROP_REASON_NOT_DROPPED) {  
  13.      //這個方法就是設置插入結果,根據不同InjectionRest彈出不同LOG  
  14.         setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY  
  15.                 ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);  
  16.         return true;  
  17.     }  
  18.  //判斷時間的類型  
  19.  bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;  
  20.    //獲得事件的接受者或者實際響應者  
  21.     // Identify targets.  
  22.     Vector<InputTarget> inputTargets;  
  23.     bool conflictingPointerActions = false;  
  24.     int32_t injectionResult;  
  25.     if (isPointerEvent) {  
  26.         // Pointer event.  (eg. touchscreen)  
  27.         // 獲得對應的window 是 touch 事件,這裏是重點  
  28.        injectionResult = findTouchedWindowTargetsLocked(currentTime,  
  29.                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);  
  30.     } else {  
  31.        // Non touch event.  (eg. trackball)  
  32.         // 是軌跡事件  
  33.         injectionResult = findFocusedWindowTargetsLocked(currentTime,  
  34.                 entry, inputTargets, nextWakeupTime);  
  35.     }  
  36.     // 是否延遲處理  
  37.     if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {  
  38.         return false;  
  39.     }  
  40. // 設置延遲處理  
  41. setInjectionResultLocked(entry, injectionResult);  
  42.     if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {  
  43.         if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {  
  44.             CancelationOptions::Mode mode(isPointerEvent ?  
  45.                     CancelationOptions::CANCEL_POINTER_EVENTS :  
  46.                     CancelationOptions::CANCEL_NON_POINTER_EVENTS);  
  47.             CancelationOptions options(mode, "input event injection failed");  
  48.             synthesizeCancelationEventsForMonitorsLocked(options);  
  49.         }  
  50.         return true;  
  51.     }  
  52.     //支持 發送二次輸入顯示器的顯示事件  
  53.     // TODO: support sending secondary display events to input monitors  
  54.     if (isMainDisplay(entry->displayId)) {  
  55.         addMonitoringTargetsLocked(inputTargets);  
  56.     }  
  57. // Dispatch the motion.  
  58.     if (conflictingPointerActions) {  
  59.         CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,  
  60.                 "conflicting pointer actions");  
  61.         synthesizeCancelationEventsForAllConnectionsLocked(options);  
  62.     }  
  63.     dispatchEventLocked(currentTime, entry, inputTargets);  
  64.     return true;  
  65. }  
   bool InputDispatcher::dispatchMotionLocked(
           nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
       //進行motion事件,進行處理
       // Preprocessing.
       if (! entry->dispatchInProgress) {
           entry->dispatchInProgress = true;
           //這個函數把motion的相關值打出來
           logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
       }
    // Clean up if dropping the event.
   把舊有的數據清楚掉
       if (*dropReason != DROP_REASON_NOT_DROPPED) {
        //這個方法就是設置插入結果,根據不同InjectionRest彈出不同LOG
           setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
                   ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
           return true;
       }
    //判斷時間的類型
    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
      //獲得事件的接受者或者實際響應者
       // Identify targets.
       Vector<InputTarget> inputTargets;
       bool conflictingPointerActions = false;
       int32_t injectionResult;
       if (isPointerEvent) {
           // Pointer event.  (eg. touchscreen)
           // 獲得對應的window 是 touch 事件,這裏是重點
          injectionResult = findTouchedWindowTargetsLocked(currentTime,
                  entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
       } else {
          // Non touch event.  (eg. trackball)
           // 是軌跡事件
           injectionResult = findFocusedWindowTargetsLocked(currentTime,
                   entry, inputTargets, nextWakeupTime);
       }
       // 是否延遲處理
       if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
           return false;
       }
   // 設置延遲處理
   setInjectionResultLocked(entry, injectionResult);
       if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
           if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
               CancelationOptions::Mode mode(isPointerEvent ?
                       CancelationOptions::CANCEL_POINTER_EVENTS :
                       CancelationOptions::CANCEL_NON_POINTER_EVENTS);
               CancelationOptions options(mode, "input event injection failed");
               synthesizeCancelationEventsForMonitorsLocked(options);
           }
           return true;
       }
       //支持 發送二次輸入顯示器的顯示事件
       // TODO: support sending secondary display events to input monitors
       if (isMainDisplay(entry->displayId)) {
           addMonitoringTargetsLocked(inputTargets);
       }
   // Dispatch the motion.
       if (conflictingPointerActions) {
           CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                   "conflicting pointer actions");
           synthesizeCancelationEventsForAllConnectionsLocked(options);
       }
       dispatchEventLocked(currentTime, entry, inputTargets);
       return true;
   }
          這裏大概就是touch事件的處理流程, findTouchedWindowTargetsLocked 是找到對應的事件響應者的重要方法,下面開始詳細說明
         
  1. Code In InputDispatcher  
  2. int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,  
  3.         const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {  
  4.     int32_t injectionResult;  
  5.     String8 reason;  
   Code In InputDispatcher
   int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
           const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
       int32_t injectionResult;
       String8 reason;
//這裏判斷是否有焦點的窗口跟焦點的應用
// If there is no currently focused window and no focused application // then drop the event. if (mFocusedWindowHandle == NULL) { if (mFocusedApplicationHandle != NULL) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, NULL, nextWakeupTime, "Waiting because no window has focus but there is a " "focused application that may eventually add a window " "when it finishes starting up."); goto Unresponsive; }
  1.            ALOGI("Dropping event because there is no focused window or focused application.");  
  2.         injectionResult = INPUT_EVENT_INJECTION_FAILED;  
  3.         goto Failed;  
  4.     }  
  1.     // Check permissions.   檢查權限  
  2.     if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {  
  3.         injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;  
  4.         goto Failed;  
  5.     }  
    // Check permissions.   檢查權限
    if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
        injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
        goto Failed;
    }
  1. // Check whether the window is ready for more input.  
    // Check whether the window is ready for more input.
  1.     // 檢查窗口的狀態,比如是否pause 等等  
  2.     reason = checkWindowReadyForMoreInputLocked(currentTime,  
  3.             mFocusedWindowHandle, entry, "focused");  
  4.     if (!reason.isEmpty()) {  
  5.         injectionResult = handleTargetsNotReadyLocked(currentTime, entry,  
  6.                 mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());  
  7.         goto Unresponsive;  
  8.     }  
    // 檢查窗口的狀態,比如是否pause 等等
    reason = checkWindowReadyForMoreInputLocked(currentTime,
            mFocusedWindowHandle, entry, "focused");
    if (!reason.isEmpty()) {
        injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());
        goto Unresponsive;
    }
  1. // Success!  Output targets.  
    // Success!  Output targets.
  1.     // 這裏主要是Input 跟 目標窗口相關信息複製跟綁定,重點關注裏面的InputChannel,這個跟窗口年消息通信有關  
  2.     injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;  
  3.     addWindowTargetLocked(mFocusedWindowHandle,  
  4.             InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),  
  5.             inputTargets);  
    // 這裏主要是Input 跟 目標窗口相關信息複製跟綁定,重點關注裏面的InputChannel,這個跟窗口年消息通信有關
    injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
    addWindowTargetLocked(mFocusedWindowHandle,
            InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
            inputTargets);
  1.      // Done.  
  2. Failed:  
  3. Unresponsive:  
  4.     nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);  
  5.     updateDispatchStatisticsLocked(currentTime, entry,  
  6.             injectionResult, timeSpentWaitingForApplication);  
  7. #if DEBUG_FOCUS  
     // Done.
Failed:
Unresponsive:
    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
    updateDispatchStatisticsLocked(currentTime, entry,
            injectionResult, timeSpentWaitingForApplication);
#if DEBUG_FOCUS
  1.      ALOGD("findFocusedWindow finished: injectionResult=%d, "  
  2.             "timeSpentWaitingForApplication=%0.1fms",  
  3.             injectionResult, timeSpentWaitingForApplication / 1000000.0);  
  4. #endif  
  5.     return injectionResult;  
  6.   
  7.      
     ALOGD("findFocusedWindow finished: injectionResult=%d, "
            "timeSpentWaitingForApplication=%0.1fms",
            injectionResult, timeSpentWaitingForApplication / 1000000.0);
#endif
    return injectionResult;

   
               上面重點要關注的就是mFocusedWindowHandle  跟  mFocusedApplicationHandle 。他們是誰複製的呢?如何複製的呢?起什麼作用了。明白了他們兩個就可以明白了Input 跟對應的window的通信。下面就主要從這兩個對象進行研究展開。findFocusedWindowTargetsLocked 的方法裏面其他就是檢查窗口狀態等相關信息。

             mFocusedWindowHandler 誰複製的呢?經過查詢在InputDispatcher 裏面就如下的方法     

  1. void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {  
  2. Code 省略  
  3. // newFocusedWindowHandler  
  4. sp<InputWindowHandle> newFocusedWindowHandle;  
  5. //mFocusedWindowHandler 是被賦值爲newFocusedWindowHandle  
  6. mFocusedWindowHandle = newFocusedWindowHandle;  
  7. Code 省略  
      void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
      Code 省略
      // newFocusedWindowHandler
      sp<InputWindowHandle> newFocusedWindowHandle;
      //mFocusedWindowHandler 是被賦值爲newFocusedWindowHandle
      mFocusedWindowHandle = newFocusedWindowHandle;
      Code 省略
            這裏就是InputDispatcher 設置對應的消息輸出窗口的地方,但是到底這個方法到底誰在用?什麼地方用?由於咱們討論的是IMS 整個體系,InputDispatcher跟InputReader 是IMS 的左膀右臂。InputReader是負責的讀取的數據然後應該是給IMS 去處理,InputDispatcher 是分發的,應該也是由IMS 去具體處理。咱們去IMS看看是否有設置窗口的調用

            看下InputManagerService.java

           代碼路徑:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

            public void setInputWindows(InputWindowHandle[] windowHandles) {

  1. //這裏調用com_android_server_input_InputManagerService.cpp  
  2.       nativeSetInputWindows(mPtr, windowHandles);  
  3. }  
      //這裏調用com_android_server_input_InputManagerService.cpp
            nativeSetInputWindows(mPtr, windowHandles);
      }
            代碼路徑:frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

  1. void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {  
  2.  Vector<sp<InputWindowHandle> > windowHandles;  
  3.  if (windowHandleObjArray) {  
  4.      jsize length = env->GetArrayLength(windowHandleObjArray);  
  5.     for (jsize i = 0; i < length; i++) {  
  6.          jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);  
  7.          if (! windowHandleObj) {  
  8.              break// found null element indicating end of used portion of the array  
  9.          }  
  10.          sp<InputWindowHandle> windowHandle =  
  11.                  android_server_InputWindowHandle_getHandle(env, windowHandleObj);  
  12.          if (windowHandle != NULL) {  
  13.              windowHandles.push(windowHandle);  
  14.          }  
  15.          env->DeleteLocalRef(windowHandleObj);  
  16.      }  
  17.  }  
  18.  //這裏會調用InputManager.cpp裏面的方法  
  19.  mInputManager->getDispatcher()->setInputWindows(windowHandles);  
  20.  CODE 省略  
      void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
       Vector<sp<InputWindowHandle> > windowHandles;
       if (windowHandleObjArray) {
           jsize length = env->GetArrayLength(windowHandleObjArray);
          for (jsize i = 0; i < length; i++) {
               jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
               if (! windowHandleObj) {
                   break; // found null element indicating end of used portion of the array
               }
               sp<InputWindowHandle> windowHandle =
                       android_server_InputWindowHandle_getHandle(env, windowHandleObj);
               if (windowHandle != NULL) {
                   windowHandles.push(windowHandle);
               }
               env->DeleteLocalRef(windowHandleObj);
           }
       }
       //這裏會調用InputManager.cpp裏面的方法
       mInputManager->getDispatcher()->setInputWindows(windowHandles);
       CODE 省略
             代碼路徑:frameworks/native/services/inputflinger/inputManager.cpp

  1. sp<InputDispatcherInterface> InputManager::getDispatcher() {  
  2. //獲得InputDispatcheer.cpp 對象     
  3. return mDispatcher;  
      sp<InputDispatcherInterface> InputManager::getDispatcher() {
      //獲得InputDispatcheer.cpp 對象   
      return mDispatcher;
            從上面可以知道IMS 到 InputDispather 如何層層調用setInputWindow的流程,但是這個方法還是在IMS 體系裏面調用,外面別人如何調用呢?既然從IMS 體系找不到,就從外面找,window 的管理者WMS。

            代碼路徑:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

            看下WMS 的 addWindow方法            

  1.  Code In WindowManagerService.java  
  2.  public int addWindow(Session session, IWindow client, int seq,  
  3.             WindowManager.LayoutParams attrs, int viewVisibility, int displayId,  
  4.             Rect outContentInsets, Rect outStableInsets, Rect outOutsets,  
  5.             InputChannel outInputChannel) {  
  6.  Code 省略  
  7. if (focusChanged) {  
  8. //調用InputMonitor的方法設置接收窗口  
  9.               mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);  
  10.           }  
  11.           mInputMonitor.updateInputWindowsLw(false /*force*/);  
  12. Code 省略  
      Code In WindowManagerService.java
      public int addWindow(Session session, IWindow client, int seq,
                 WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
                 Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
                 InputChannel outInputChannel) {
      Code 省略
     if (focusChanged) {
     //調用InputMonitor的方法設置接收窗口
                   mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
               }
               mInputMonitor.updateInputWindowsLw(false /*force*/);
     Code 省略
          來看下InputMonitor 在幹啥

          代碼路徑:frameworks/base/services/core/java/com/android/server/wm/inputMonitor.java

  1. /* Called when the current input focus changes. 
  2.  * Layer assignment is assumed to be complete by the time this is called. 
  3.  */  
  4.  public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {  
  5.      if (WindowManagerService.DEBUG_FOCUS_LIGHT || WindowManagerService.DEBUG_INPUT) {  
  6.          Slog.d(WindowManagerService.TAG, "Input focus has changed to " + newWindow);  
  7.      }  
  8.       if (newWindow != mInputFocus) {  
  9.           if (newWindow != null && newWindow.canReceiveKeys()) {  
  10.               // Displaying a window implicitly causes dispatching to be unpaused.  
  11.               // This is to protect against bugs if someone pauses dispatching but  
  12.               // forgets to resume.  
  13.               newWindow.mToken.paused = false;  
  14.           }  
  15.           mInputFocus = newWindow;  
  16.           setUpdateInputWindowsNeededLw();  
  17.           if (updateInputWindows) {  
  18.           //更新當前焦點窗口  
  19.               updateInputWindowsLw(false /*force*/);  
  20.           }  
  21.       }  
  22.   }  
     /* Called when the current input focus changes.
      * Layer assignment is assumed to be complete by the time this is called.
      */
      public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
          if (WindowManagerService.DEBUG_FOCUS_LIGHT || WindowManagerService.DEBUG_INPUT) {
              Slog.d(WindowManagerService.TAG, "Input focus has changed to " + newWindow);
          }
           if (newWindow != mInputFocus) {
               if (newWindow != null && newWindow.canReceiveKeys()) {
                   // Displaying a window implicitly causes dispatching to be unpaused.
                   // This is to protect against bugs if someone pauses dispatching but
                   // forgets to resume.
                   newWindow.mToken.paused = false;
               }
               mInputFocus = newWindow;
               setUpdateInputWindowsNeededLw();
               if (updateInputWindows) {
               //更新當前焦點窗口
                   updateInputWindowsLw(false /*force*/);
               }
           }
       }
  1. /* Updates the cached window information provided to the input dispatcher. */  
  2.     public void updateInputWindowsLw(boolean force) {  
  3.         if (!force && !mUpdateInputWindowsNeeded) {  
  4.             return;  
  5.         }  
  6. Code  省略  
  7. //在這個方法裏面會調用InputManagerService的setInputWindow方法傳入  
  8. //inputWindowHandlers  
  9.  // Send windows to native code.  
  10.         mService.mInputManager.setInputWindows(mInputWindowHandles);  
  11.  // Clear the list in preparation for the next round.  
  12.         clearInputWindowHandlesLw();  
  13.         if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw");  
  14.     }  
   /* Updates the cached window information provided to the input dispatcher. */
       public void updateInputWindowsLw(boolean force) {
           if (!force && !mUpdateInputWindowsNeeded) {
               return;
           }
   Code  省略
   //在這個方法裏面會調用InputManagerService的setInputWindow方法傳入
   //inputWindowHandlers
    // Send windows to native code.
           mService.mInputManager.setInputWindows(mInputWindowHandles);
    // Clear the list in preparation for the next round.
           clearInputWindowHandlesLw();
           if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw");
       }
           到這裏就實現了WMS 通過InputMonitor 跟IMS 再 InputDispather的溝通,也就是Window 跟 Input事件的溝通了。說完他們之間的關係,就說最後一部分他們的通信渠道了。先說結論對應的window 跟  IMS 通信實際是用InputChannel。InputChannel是一個pipe,底層實際是通過socket進行通信。

         看下inputChannel的源碼:

        代碼路徑:frameworks\base\core\java\android\view\InputChannel.java

  1. Creates a new input channel pair.  One channel should be provided to the input  
  2.  * dispatcher and the other to the application's input queue.  
  3.  * @param name The descriptive (non-unique) name of the channel pair.  
  4.  * @return A pair of input channels.  The first channel is designated as the  
  5.  * server channel and should be used to publish input events.  The second channel  
  6.  * is designated as the client channel and should be used to consume input events.  
  7.  public static InputChannel[] openInputChannelPair(String name) {  
  8.     if (name == null) {  
  9.         throw new IllegalArgumentException("name must not be null");  
  10.     }  
  11.   
  12.     if (DEBUG) {  
  13.         Slog.d(TAG, "Opening input channel pair '" + name + "'");  
  14.     }  
    Creates a new input channel pair.  One channel should be provided to the input
     * dispatcher and the other to the application's input queue.
     * @param name The descriptive (non-unique) name of the channel pair.
     * @return A pair of input channels.  The first channel is designated as the
     * server channel and should be used to publish input events.  The second channel
     * is designated as the client channel and should be used to consume input events.
     public static InputChannel[] openInputChannelPair(String name) {
        if (name == null) {
            throw new IllegalArgumentException("name must not be null");
        }

        if (DEBUG) {
            Slog.d(TAG, "Opening input channel pair '" + name + "'");
        }
  1.    //這裏還要走底層的代碼  
  2.     return nativeOpenInputChannelPair(name);  
  3. }  
       //這裏還要走底層的代碼
        return nativeOpenInputChannelPair(name);
    }
        代碼路徑:frameworks\base\core\jni\android_view_InputChannel.cpp
  1. static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,  
  2.      jclass clazz, jstring nameObj) {  
  3.  const char* nameChars = env->GetStringUTFChars(nameObj, NULL);  
  4.  String8 name(nameChars);  
  5.  env->ReleaseStringUTFChars(nameObj, nameChars);  
  6.  //這裏主要是建立了一堆通信的inputchannel  
  7.  sp<InputChannel> serverChannel;  
  8.  sp<InputChannel> clientChannel;  
  9.  status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);  
   static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
    String8 name(nameChars);
    env->ReleaseStringUTFChars(nameObj, nameChars);
    //這裏主要是建立了一堆通信的inputchannel
    sp<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
  1. 代碼省略  
    代碼省略
       上面代碼說明了爲了通信,建立了一對inputChannel,那如何跟socket關聯了?看下面的代碼

     代碼路徑:frameworks\native\libs\input\InputTransport.cpp

  1. status_t InputChannel::openInputChannelPair(const String8& name,  
  2.         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {  
  3.     int sockets[2];  
  4.     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {  
  5.         status_t result = -errno;  
  6.         ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",  
  7.                 name.string(), errno);  
  8.         outServerChannel.clear();  
  9.         outClientChannel.clear();  
  10.         return result;  
  11.     }  
  12.  int bufferSize = SOCKET_BUFFER_SIZE;  
  13.     setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));  
  14.     setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));  
  15.     setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));  
  16.     setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));  
  17. String8 serverChannelName = name;  
  18.     serverChannelName.append(" (server)");  
  19.     outServerChannel = new InputChannel(serverChannelName, sockets[0]);  
  20.   
  21.     String8 clientChannelName = name;  
  22.     clientChannelName.append(" (client)");  
  23.     outClientChannel = new InputChannel(clientChannelName, sockets[1]);  
  24.     return OK;  
status_t InputChannel::openInputChannelPair(const String8& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        status_t result = -errno;
        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
                name.string(), errno);
        outServerChannel.clear();
        outClientChannel.clear();
        return result;
    }
 int bufferSize = SOCKET_BUFFER_SIZE;
    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
String8 serverChannelName = name;
    serverChannelName.append(" (server)");
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    String8 clientChannelName = name;
    clientChannelName.append(" (client)");
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
這個其實說明了inputChannel的open方法其實就是建立了socket通信

IMS體系建立了inputChannel,那WMS也相應的做了InputChannel的相關操作

代碼路徑:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

  1. public int addWindow(Session session, IWindow client, int seq,  
  2.             WindowManager.LayoutParams attrs, int viewVisibility, int displayId,  
  3.             Rect outContentInsets, Rect outStableInsets, Rect outOutsets,  
  4.             InputChannel outInputChannel) {  
  5.         int[] appOp = new int[1];  
  6.         int res = mPolicy.checkAddPermission(attrs, appOp);  
  7.         if (res != WindowManagerGlobal.ADD_OKAY) {  
  8. CODE 省略  
  9. if (outInputChannel != null && (attrs.inputFeatures  
  10.                     & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  11.                 /** M: [ALPS00044207] @{ */  
  12.                 try {  
  13.                    //設置當前通道的名字  
  14.                     String name = win.makeInputChannelName();  
  15.                    //打開一對通道  
  16.                     InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);  
  17.                     win.setInputChannel(inputChannels[0]);  
  18.                     inputChannels[1].transferTo(outInputChannel);  
  19.                     mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);  
  20.                 } catch (IllegalArgumentException e) {  
  21.                     Slog.w(TAG, "handle Input channel erorr", e);  
  22.                     return WindowManagerGlobal.ADD_INPUTCHANNEL_NOT_ALLOWED;  
  23.                 }  
  24.                 /** @} */  
  25.             }  
   public int addWindow(Session session, IWindow client, int seq,
               WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
               Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
               InputChannel outInputChannel) {
           int[] appOp = new int[1];
           int res = mPolicy.checkAddPermission(attrs, appOp);
           if (res != WindowManagerGlobal.ADD_OKAY) {
   CODE 省略
   if (outInputChannel != null && (attrs.inputFeatures
                       & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                   /** M: [ALPS00044207] @{ */
                   try {
                      //設置當前通道的名字
                       String name = win.makeInputChannelName();
                      //打開一對通道
                       InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
                       win.setInputChannel(inputChannels[0]);
                       inputChannels[1].transferTo(outInputChannel);
                       mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
                   } catch (IllegalArgumentException e) {
                       Slog.w(TAG, "handle Input channel erorr", e);
                       return WindowManagerGlobal.ADD_INPUTCHANNEL_NOT_ALLOWED;
                   }
                   /** @} */
               }

到了這裏基本IMS 關於消息的處理至少在framework層講得差不多了。做個總結吧,也把開頭的問題回答下,其實文中已經說得很清楚了。

重點的幾個問題概述下:

InputManager初始化跟其他的核心service一樣都是在systemServer裏面進行(這裏估計有問題),初始化後,會調用start方法。其實調用的是native層inputmanager的start方法,這裏初始化了兩個線程。native層的inputmanager的構造函數裏面會對InputReader/ InputDispatcher進行初始化,Eventhub(讀取dev/input裏面的事件)和InputDispatcher作爲參數傳給了InputReader

Work
一:消息處理,inputReader通過EventHub獲得數據後,會通知QueuedInputListener調用flush方法,由上面的詳細筆記可以知道QueuedInputListener繼承InputListenerInterface,InputListenerInterface 是繼承Refbase,InputDispatcher作爲參數傳給了QueuedInputListener。
二:QueuedInputListener.flush方法會調用子類的notify方法,至於notify是key,還是其他,具體情況具體處理。
Inputdispatcher跟WMS的交互,主要在findfocuswindow函數裏面實現,關鍵在setWindow方法傳遞windowHandler。
setWindow方法都是通過成員變量調方法,進行windowHandler傳遞。WMS裏面有inputmonitor作爲成員變量在裏面,在InputMonitor裏面會調用native InputManagerService的setInputWindow方法,在這個方法裏面會通過InputManager調用inputDispatcher方法裏面的setInputWindow方法,完成windowHandler的傳遞。
三:可以知道windowHandler上面有inputChannel,inputChannel是android裏面的pipe 管道通信。實現了應用程序跟InputDispatcher的通信
注:mQueuedListener->flush();如何跟InputDispatcher聯繫上?
在InputRead.cpp的構造函數裏面,inputDispatcher作爲參數傳給了QueuedInputListener裏。
QueuedInputListener定義在InputListener.h 裏面,InputDispatcher作爲參數,到了QueuedInputListener的構造函數裏,傳給mInnerListener()這個方法裏面

問題:那他如何或者跟其他模塊配合獲取事件?並且把這個事件進行分發?如何準確定位對應的處理事件的模塊?

1.其實通過調用,裏面有對應的對象調用相對的方法,進行配合使用。

2.分發其實找到對應的window ,然後會建立對應的一對inputchannel進行通信。

Ok,寫完了,其實去年就寫完了,一直沒時間整理髮博客。今天大概全部整理了下發出來了。希望能跟各位多多交流。吐槽一句CSDN的博客真不好編輯代碼的。


發佈了16 篇原創文章 · 獲贊 21 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章