1. 程式人生 > >Android輸入輸出機制之來龍去脈之前生後世

Android輸入輸出機制之來龍去脈之前生後世

先講一下基本一般的輸入處理方式的知識。一般的輸入輸出採用生產者,消費者模式,並構造佇列進行處理,如下圖

  

這種輸入模型在android的系統中很多地方採用,先從最底層說起:

 為了由於觸屏事件頻率很高,android設計者講一個迴圈執行緒,拆分為兩級迴圈,並做了個佇列來進行緩衝。


InputDispatcherThread和InputReaderThread

         InputDispatcherThread在自己的迴圈中對InputReaderThread請求同步,InputReaderThread收到同步訊號後,把事件放入InputDispatcher的佇列中。

具體程式碼如下:

InputReader.cpp中有很多InputMapper,有SwitchInputMapper,KeyBoardInputMapper,TrackballInputMapper,SingleTouchInputMapper,

MultiTouchInputMapper。當執行緒從EventHub讀取到Event後,呼叫這些InputMapper的pocess方法:

[java] view plaincopyprint?
  1. 檔案InputReader.cpp中:  
  2. bool InputReaderThread::threadLoop() {  
  3.     mReader->loopOnce();  
  4.     returntrue;  
  5. }  
  6. void InputReader::loopOnce() {  
  7.     RawEvent rawEvent;  
  8.     mEventHub->getEvent(& rawEvent);  
  9. #if DEBUG_RAW_EVENTS  
  10.     LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d",  
  11.             rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,  
  12.             rawEvent.value);  
  13. #endif  
  14.     process(& rawEvent);  
  15. }  
檔案InputReader.cpp中:

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}


void InputReader::loopOnce() {
    RawEvent rawEvent;
    mEventHub->getEvent(& rawEvent);

#if DEBUG_RAW_EVENTS
    LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d",
            rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,
            rawEvent.value);
#endif

    process(& rawEvent);
}

 process如下

[java] view plaincopyprint?
  1. void InputReader::process(const RawEvent* rawEvent) {  
  2.     switch (rawEvent->type) {  
  3.         consumeEvent(rawEvent);  
  4.         break;  
  5.     }  
  6. }  
void InputReader::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
        consumeEvent(rawEvent);
        break;
    }
}
Java程式碼 複製程式碼 收藏程式碼
  1. consumeEvent(rawEvent);  
[java] view plaincopyprint?
  1. consumeEvent(rawEvent);  
consumeEvent(rawEvent);

方法是關鍵,下面繼續跟進;

Java程式碼 複製程式碼 收藏程式碼 [java] view plaincopyprint?
  1. void InputReader::consumeEvent(const RawEvent* rawEvent) {  
  2.     int32_t deviceId = rawEvent->deviceId;  
  3.     {   
  4.         device->process(rawEvent);  
  5.     } // release device registry reader lock
  6. }  
void InputReader::consumeEvent(const RawEvent* rawEvent) {
    int32_t deviceId = rawEvent->deviceId;

    { 
        device->process(rawEvent);
    } // release device registry reader lock
}

   device->process(rawEvent)行, 跟進去:

Java程式碼 複製程式碼 收藏程式碼 [java] view plaincopyprint?
  1. void InputDevice::process(const RawEvent* rawEvent) {  
  2.     size_t numMappers = mMappers.size();  
  3.     for (size_t i = 0; i < numMappers; i++) {  
  4.         InputMapper* mapper = mMappers[i];  
  5.         mapper->process(rawEvent);  
  6.     }  
  7. }  
void InputDevice::process(const RawEvent* rawEvent) {
    size_t numMappers = mMappers.size();
    for (size_t i = 0; i < numMappers; i++) {
        InputMapper* mapper = mMappers[i];
        mapper->process(rawEvent);
    }
}

 下面進入了IputMapper,InputMapper是個純虛類,process是個純虛方法,隨便找個例子跟進去:

[cpp] view plaincopyprint?
  1. void SingleTouchInputMapper::process(const RawEvent* rawEvent) {  
  2.     switch (rawEvent->type) {  
  3.     case EV_KEY:  
  4.         switch (rawEvent->scanCode) {  
  5.         case BTN_TOUCH:  
  6.             mAccumulator.fields |= Accumulator::FIELD_BTN_TOUCH;  
  7.             mAccumulator.btnTouch = rawEvent->value != 0;  
  8.             // Don't sync immediately.  Wait until the next SYN_REPORT since we might
  9.             // not have received valid position information yet.  This logic assumes that
  10.             // BTN_TOUCH is always followed by SYN_REPORT as part of a complete packet.
  11.             break;  
  12.         }  
  13.         break;  
  14.     case EV_SYN:  
  15.         switch (rawEvent->scanCode) {  
  16.         case SYN_REPORT:  
  17.             sync(rawEvent->when);  
  18.             break;  
  19.         }  
  20.         break;  
  21.     }  
  22. }  
void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
    case EV_KEY:
        switch (rawEvent->scanCode) {
        case BTN_TOUCH:
            mAccumulator.fields |= Accumulator::FIELD_BTN_TOUCH;
            mAccumulator.btnTouch = rawEvent->value != 0;
            // Don't sync immediately.  Wait until the next SYN_REPORT since we might
            // not have received valid position information yet.  This logic assumes that
            // BTN_TOUCH is always followed by SYN_REPORT as part of a complete packet.
            break;
        }
        break;
    case EV_SYN:
        switch (rawEvent->scanCode) {
        case SYN_REPORT:
            sync(rawEvent->when);
            break;
        }
        break;
    }
}

 最關鍵的是

Cpp程式碼 複製程式碼 收藏程式碼
  1. sync(rawEvent->when);  
[cpp] view plaincopyprint?
  1. sync(rawEvent->when);  
 sync(rawEvent->when);

  展開如下:

Cpp程式碼 複製程式碼 收藏程式碼 [cpp] view plaincopyprint?
  1. void SingleTouchInputMapper::sync(nsecs_t when) {  
  2.     syncTouch(when, true);  
  3. }  
void SingleTouchInputMapper::sync(nsecs_t when) {

    syncTouch(when, true);

 
}
Java程式碼 複製程式碼 收藏程式碼 [java] view plaincopyprint?
  1. void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {  
  2.     if (touchResult == DISPATCH_TOUCH) {  
  3.         detectGestures(when);  
  4.         dispatchTouches(when, policyFlags);  
  5.     }  
  6. }  
void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
   
    if (touchResult == DISPATCH_TOUCH) {
        detectGestures(when);
        dispatchTouches(when, policyFlags);
    }
}

 這兩行,一個是虛擬鍵盤,一個是觸控式螢幕。

      TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);

Java程式碼 複製程式碼 收藏程式碼
  1. dispatchTouches  
  2. Cpp程式碼 複製程式碼 收藏程式碼
    1. void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {   
    2. // Dispatch pointer down events using the new pointer locations.
    3. while (!downIdBits.isEmpty()) {   
    4.             dispatchTouch(when, policyFlags, &mCurrentTouch,   
    5.                     activeIdBits, downId, pointerCount, motionEventAction);   
    6.         }   
    7.     }   
    8. }  
    [cpp] view plaincopyprint?
    1. void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {  
    2.         // Dispatch pointer down events using the new pointer locations.
    3.         while (!downIdBits.isEmpty()) {  
    4.             dispatchTouch(when, policyFlags, &mCurrentTouch,  
    5.                     activeIdBits, downId, pointerCount, motionEventAction);  
    6.         }  
    7.     }  
    8. }  
    void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
            // Dispatch pointer down events using the new pointer locations.
            while (!downIdBits.isEmpty()) {
                dispatchTouch(when, policyFlags, &mCurrentTouch,
                        activeIdBits, downId, pointerCount, motionEventAction);
            }
        }
    }
    
      Cpp程式碼 複製程式碼 收藏程式碼
    1. dispatchTouch(when, policyFlags, &mCurrentTouch,   
    2.                     activeIdBits, downId, pointerCount, motionEventAction);  
    [cpp] view plaincopyprint?
    1. dispatchTouch(when, policyFlags, &mCurrentTouch,  
    2.                     activeIdBits, downId, pointerCount, motionEventAction);  
    dispatchTouch(when, policyFlags, &mCurrentTouch,
                        activeIdBits, downId, pointerCount, motionEventAction);

    這個方法展開如下:

    Java程式碼 複製程式碼 收藏程式碼
    1. void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,   
    2.         TouchData* touch, BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,   
    3.         int32_t motionEventAction) {   
    4.     int32_t pointerIds[MAX_POINTERS];   
    5.     PointerCoords pointerCoords[MAX_POINTERS];   
    6.     int32_t motionEventEdgeFlags = 0;   
    7. float xPrecision, yPrecision;   
    8.     {    
    9.     getDispatcher()->notifyMotion(when, getDeviceId(), getSources(), policyFlags,   
    10.             motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,   
    11.             pointerCount, pointerIds, pointerCoords,   
    12.             xPrecision, yPrecision, mDownTime);   
    13. }  
    [java] view plaincopyprint?
    1. void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,  
    2.         TouchData* touch, BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,  
    3.         int32_t motionEventAction) {  
    4.     int32_t pointerIds[MAX_POINTERS];  
    5.     PointerCoords pointerCoords[MAX_POINTERS];  
    6.     int32_t motionEventEdgeFlags = 0;  
    7.     float xPrecision, yPrecision;  
    8.     {   
    9.     getDispatcher()->notifyMotion(when, getDeviceId(), getSources(), policyFlags,  
    10.             motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,  
    11.             pointerCount, pointerIds, pointerCoords,  
    12.             xPrecision, yPrecision, mDownTime);  
    13. }  
    void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
            TouchData* touch, BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
            int32_t motionEventAction) {
        int32_t pointerIds[MAX_POINTERS];
        PointerCoords pointerCoords[MAX_POINTERS];
        int32_t motionEventEdgeFlags = 0;
        float xPrecision, yPrecision;
    
        { 
        getDispatcher()->notifyMotion(when, getDeviceId(), getSources(), policyFlags,
                motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
                pointerCount, pointerIds, pointerCoords,
                xPrecision, yPrecision, mDownTime);
    }
    
     

      這樣就到了InputDiaptcher的notifyMotion方法,這個方法很長,都再處理MOVE事件,將無用的刪除後,留下如下關鍵程式碼:

    Java程式碼 複製程式碼 收藏程式碼
    1. void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,   
    2.         uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t edgeFlags,   
    3.         uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,   
    4. float xPrecision, float yPrecision, nsecs_t downTime) {         
    5. // Just enqueue a new motion event.
    6.         MotionEntry* newEntry = mAllocator.obtainMotionEntry(eventTime,   
    7.                 deviceId, source, policyFlags, action, flags, metaState, edgeFlags,   
    8.                 xPrecision, yPrecision, downTime,   
    9.                 pointerCount, pointerIds, pointerCoords);   
    10.         needWake = enqueueInboundEventLocked(newEntry);   
    11. }  
    [java] view plaincopyprint?
    1. void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,  
    2.         uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t edgeFlags,  
    3.         uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,  
    4.         float xPrecision, float yPrecision, nsecs_t downTime) {        
    5.  // Just enqueue a new motion event.
    6.         MotionEntry* newEntry = mAllocator.obtainMotionEntry(eventTime,  
    7.                 deviceId, source, policyFlags, action, flags, metaState, edgeFlags,  
    8.                 xPrecision, yPrecision, downTime,  
    9.                 pointerCount, pointerIds, pointerCoords);  
    10.         needWake = enqueueInboundEventLocked(newEntry);  
    11. }  
     void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
            uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t edgeFlags,
            uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
            float xPrecision, float yPrecision, nsecs_t downTime) {      
    
     // Just enqueue a new motion event.
            MotionEntry* newEntry = mAllocator.obtainMotionEntry(eventTime,
                    deviceId, source, policyFlags, action, flags, metaState, edgeFlags,
                    xPrecision, yPrecision, downTime,
                    pointerCount, pointerIds, pointerCoords);
    
            needWake = enqueueInboundEventLocked(newEntry);
    }

     最後一句:

    Java程式碼 複製程式碼 收藏程式碼
    1. needWake = enqueueInboundEventLocked(newEntry);  
    [java] view plaincopyprint?
    1. needWake = enqueueInboundEventLocked(newEntry);  
     needWake = enqueueInboundEventLocked(newEntry);
    Cpp程式碼 複製程式碼 收藏程式碼
    1. bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {   
    2. bool needWake = mInboundQueue.isEmpty();   
    3.     mInboundQueue.enqueueAtTail(entry);   
    4. switch (entry->type) {   
    5. case EventEntry::TYPE_KEY: {   
    6.         KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);   
    7. if (isAppSwitchKeyEventLocked(keyEntry)) {   
    8. if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {   
    9.                 mAppSwitchSawKeyDown = true;   
    10.             } elseif (keyEntry->action == AKEY_EVENT_ACTION_UP) {   
    11. if (mAppSwitchSawKeyDown) {   
    12. #if DEBUG_APP_SWITCH
    13.                     LOGD("App switch is pending!");   
    14. #endif
    15.                     mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;   
    16.                     mAppSwitchSawKeyDown = false;   
    17.                     needWake = true;   
    18.                 }   
    19.             }   
    20.         }   
    21. break;   
    22.     }   
    23.     }   
    24. return needWake;   
    25. }  
    [cpp] view plaincopyprint?
    1. bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {  
    2.     bool needWake = mInboundQueue.isEmpty();  
    3.     mInboundQueue.enqueueAtTail(entry);  
    4.     switch (entry->type) {  
    5.     case EventEntry::TYPE_KEY: {  
    6.         KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);  
    7.         if (isAppSwitchKeyEventLocked(keyEntry)) {  
    8.             if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {  
    9.                 mAppSwitchSawKeyDown = true;  
    10.             } elseif (keyEntry->action == AKEY_EVENT_ACTION_UP) {  
    11.                 if (mAppSwitchSawKeyDown) {  
    12. #if DEBUG_APP_SWITCH
    13.                     LOGD("App switch is pending!");  
    14. #endif
    15.                     mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;  
    16.                     mAppSwitchSawKeyDown = false;  
    17.                     needWake = true;  
    18.                 }  
    19.             }  
    20.         }  
    21.         break;  
    22.     }  
    23.     }  
    24.     return needWake;  
    25. }  
    bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
        bool needWake = mInboundQueue.isEmpty();
        mInboundQueue.enqueueAtTail(entry);
    
        switch (entry->type) {
        case EventEntry::TYPE_KEY: {
            KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
            if (isAppSwitchKeyEventLocked(keyEntry)) {
                if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
                    mAppSwitchSawKeyDown = true;
                } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
                    if (mAppSwitchSawKeyDown) {
    #if DEBUG_APP_SWITCH
                        LOGD("App switch is pending!");
    #endif
                        mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
                        mAppSwitchSawKeyDown = false;
                        needWake = true;
                    }
                }
            }
            break;
        }
        }
    
        return needWake;
    }
    
      Cpp程式碼 複製程式碼 收藏程式碼
    1. mInboundQueue正是上面所說的佇列。到此為止,從InputReader插入到佇列就完成了。  
    [cpp] view plaincopyprint?
    1. mInboundQueue正是上面所說的佇列。到此為止,從InputReader插入到佇列就完成了。  
    mInboundQueue正是上面所說的佇列。到此為止,從InputReader插入到佇列就完成了。

     那麼InputDispatcher又是如何從佇列中取出來的呢?累了。

      InputDiapather的

    Cpp程式碼 複製程式碼 收藏程式碼
    1. dispatchOnce  
    [cpp] view plaincopyprint?
    1. dispatchOnce  
    dispatchOnce

    方法如下:

    Cpp程式碼 複製程式碼 收藏程式碼
    1. void InputDispatcher::dispatchOnce() {   
    2.     nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();   
    3.     nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay();   
    4.     nsecs_t nextWakeupTime = LONG_LONG_MAX;   
    5.     { // acquire lock
    6.         AutoMutex _l(mLock);   
    7.         dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);   
    8. if (runCommandsLockedInterruptible()) {   
    9.             nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
    10.         }   
    11.     } // release lock
    12. // Wait for callback or timeout or wake.  (make sure we round up, not down)
    13.     nsecs_t currentTime = now();   
    14.     int32_t timeoutMillis;   
    15. if (nextWakeupTime > currentTime) {   
    16.         uint64_t timeout = uint64_t(nextWakeupTime - currentTime);   
    17.         timeout = (timeout + 999999LL) / 1000000LL;   
    18.         timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);   
    19.     } else {   
    20.         timeoutMillis = 0;   
    21.     }   
    22.     mLooper->pollOnce(timeoutMillis);   
    23. }  
    [cpp] view plaincopyprint?
    1. void InputDispatcher::dispatchOnce() {  
    2.     nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();  
    3.     nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay();  
    4.     nsecs_t nextWakeupTime = LONG_LONG_MAX;  
    5.     { // acquire lock
    6.         AutoMutex _l(mLock);  
    7.         dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);  
    8.         if (runCommandsLockedInterruptible()) {  
    9.             nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
    10.         }  
    11.     } // release lock
    12.     // Wait for callback or timeout or wake.  (make sure we round up, not down)
    13.     nsecs_t currentTime = now();  
    14.     int32_t timeoutMillis;  
    15.     if (nextWakeupTime > currentTime) {  
    16.         uint64_t timeout = uint64_t(nextWakeupTime - currentTime);  
    17.         timeout = (timeout + 999999LL) / 1000000LL;  
    18.         timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);  
    19.     } else {  
    20.         timeoutMillis = 0;  
    21.     }  
    22.     mLooper->pollOnce(timeoutMillis);  
    23. }  
    void InputDispatcher::dispatchOnce() {
        nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
        nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay();
    
        nsecs_t nextWakeupTime = LONG_LONG_MAX;
        { // acquire lock
            AutoMutex _l(mLock);
            dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);
    
            if (runCommandsLockedInterruptible()) {
                nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
            }
        } // release lock
    
        // Wait for callback or timeout or wake.  (make sure we round up, not down)
        nsecs_t currentTime = now();
        int32_t timeoutMillis;
        if (nextWakeupTime > currentTime) {
            uint64_t timeout = uint64_t(nextWakeupTime - currentTime);
            timeout = (timeout + 999999LL) / 1000000LL;
            timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);
        } else {
            timeoutMillis = 0;
        }
    
        mLooper->pollOnce(timeoutMillis);
    }

     最關鍵的是

    Cpp程式碼 複製程式碼 收藏程式碼
    1. dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);  
    [cpp] view plaincopyprint?
    1. dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);  
      dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);
    

    Cpp程式碼 複製程式碼 收藏程式碼
    1.     mLooper->pollOnce(timeoutMillis);(這個方法在有個回撥,與事件有關的是【管道裝置的檔案描述符】。   
    2.   具體機制在後面講。這個東西實際上是個跨程序的訊號。傳送給了Android的使用者程序的JNI,又通過JNI呼叫InputQueue的的   
    3. 靜態方法如:dispatchMotionEvent。後面回提到dispatchMotionEvent才是Android使用者程序的事件入口函式。)   
    4. )  
    [cpp] view plaincopyprint?
    1.     mLooper->pollOnce(timeoutMillis);(這個方法在有個回撥,與事件有關的是【管道裝置的檔案描述符】。  
    2.   具體機制在後面講。這個東西實際上是個跨程序的訊號。傳送給了Android的使用者程序的JNI,又通過JNI呼叫InputQueue的的  
    3. 靜態方法如:dispatchMotionEvent。後面回提到dispatchMotionEvent才是Android使用者程序的事件入口函式。)  
    4. )  
        mLooper->pollOnce(timeoutMillis);(這個方法在有個回撥,與事件有關的是【管道裝置的檔案描述符】。
      具體機制在後面講。這個東西實際上是個跨程序的訊號。傳送給了Android的使用者程序的JNI,又通過JNI呼叫InputQueue的的
    靜態方法如:dispatchMotionEvent。後面回提到dispatchMotionEvent才是Android使用者程序的事件入口函式。)
    )

    程式碼又長又臭

    Java程式碼 複製程式碼 收藏程式碼
    1. void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,   
    2.         nsecs_t keyRepeatDelay, nsecs_t* nextWakeupTime) {   
    3. case EventEntry::TYPE_MOTION: {   
    4.         MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);   
    5. if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {   
    6.             dropReason = DROP_REASON_APP_SWITCH;   
    7.         }   
    8.         done = dispatchMotionLocked(currentTime, typedEntry,   
    9.                 &dropReason, nextWakeupTime);   
    10. break;   
    11.     }   
    12. }  
    [java] view plaincopyprint?
    1. void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,  
    2.         nsecs_t keyRepeatDelay, nsecs_t* nextWakeupTime) {  
    3.     case EventEntry::TYPE_MOTION: {  
    4.         MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);  
    5.         if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {  
    6.             dropReason = DROP_REASON_APP_SWITCH;  
    7.         }  
    8.         done = dispatchMotionLocked(currentTime, typedEntry,  
    9.                 &dropReason, nextWakeupTime);  
    10.         break;  
    11.     }  
    12. }  
    void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,
            nsecs_t keyRepeatDelay, nsecs_t* nextWakeupTime) {
        case EventEntry::TYPE_MOTION: {
            MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
            if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
                dropReason = DROP_REASON_APP_SWITCH;
            }
            done = dispatchMotionLocked(currentTime, typedEntry,
                    &dropReason, nextWakeupTime);
            break;
        }
    
    }
    
    Java程式碼 複製程式碼 收藏程式碼
    1. dispatchMotionLocked  
    [java] view plaincopyprint?
    1. dispatchMotionLocked  
    dispatchMotionLocked

    方法呼叫prepareDispatchCycleLocked,呼叫startDispatchCycleLocked,最終呼叫

           // Publish the key event.
            status = connection->inputPublisher.publishKeyEvent(keyEntry->deviceId, keyEntry->source,
                    action, flags, keyEntry->keyCode, keyEntry->scanCode,
                    keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
                    keyEntry->eventTime);

    或者 // Publish the motion event and the first motion sample.
            status = co