Android输入输出机制之来龙去脉之前生后世

 

先讲一下基本一般的输入处理方式的知识。一般的输入输出采用生产者,消费者模式,并构造队列进行处理,如下图

  

这种输入模型在android的系统中很多地方采用,先从最底层说起:

 为了由于触屏事件频率很高,android设计者讲一个循环线程,拆分为两级循环,并做了个队列来进行缓冲。


InputDispatcherThread和InputReaderThread

         InputDispatcherThread在自己的循环中对InputReaderThread请求同步,InputReaderThread收到同步信号后,把事件放入InputDispatcher的队列中。

具体代码如下:

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

MultiTouchInputMapper。当线程从EventHub读取到Event后,调用这些InputMapper的pocess方法:

 
  1. 文件InputReader.cpp中:  
  2.   
  3. bool InputReaderThread::threadLoop() {  
  4.     mReader->loopOnce();  
  5.     return true;  
  6. }  
  7.   
  8.   
  9. void InputReader::loopOnce() {  
  10.     RawEvent rawEvent;  
  11.     mEventHub->getEvent(& rawEvent);  
  12.   
  13. #if DEBUG_RAW_EVENTS  
  14.     LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d",  
  15.             rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,  
  16.             rawEvent.value);  
  17. #endif  
  18.   
  19.     process(& rawEvent);  
  20. }  
文件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如下

  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);  
  1. consumeEvent(rawEvent);  
consumeEvent(rawEvent);

方法是关键,下面继续跟进;

 

Java代码 复制代码  收藏代码
  1. void InputReader::consumeEvent(const RawEvent* rawEvent) {  
  2.     int32_t deviceId = rawEvent->deviceId;  
  3.   
  4.     {   
  5.         device->process(rawEvent);  
  6.     } // release device registry reader lock  
  7. }  
void InputReader::consumeEvent(const RawEvent* rawEvent) {
    int32_t deviceId = rawEvent->deviceId;

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

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

Java代码 复制代码  收藏代码
  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是个纯虚方法,随便找个例子跟进去:

  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);  
  1. sync(rawEvent->when);  
 sync(rawEvent->when);

  展开如下:

 

Cpp代码 复制代码  收藏代码
  1. void SingleTouchInputMapper::sync(nsecs_t when) {  
  2.   
  3.     syncTouch(when, true);  
  4.   
  5.    
  6. }  
void SingleTouchInputMapper::sync(nsecs_t when) {

    syncTouch(when, true);

 
}

 

Java代码 复制代码  收藏代码
  1. void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {  
  2.      
  3.     if (touchResult == DISPATCH_TOUCH) {  
  4.         detectGestures(when);  
  5.         dispatchTouches(when, policyFlags);  
  6.     }  
  7. }  
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. }  
    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);  
    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.     {    
    10.     getDispatcher()->notifyMotion(when, getDeviceId(), getSources(), policyFlags,   
    11.             motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,   
    12.             pointerCount, pointerIds, pointerCoords,   
    13.             xPrecision, yPrecision, mDownTime);   
    14. }  
    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.     {   
    10.     getDispatcher()->notifyMotion(when, getDeviceId(), getSources(), policyFlags,  
    11.             motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,  
    12.             pointerCount, pointerIds, pointerCoords,  
    13.             xPrecision, yPrecision, mDownTime);  
    14. }  
    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.   
    6.  // Just enqueue a new motion event.   
    7.         MotionEntry* newEntry = mAllocator.obtainMotionEntry(eventTime,   
    8.                 deviceId, source, policyFlags, action, flags, metaState, edgeFlags,   
    9.                 xPrecision, yPrecision, downTime,   
    10.                 pointerCount, pointerIds, pointerCoords);   
    11.   
    12.         needWake = enqueueInboundEventLocked(newEntry);   
    13. }  
    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.   
    6.  // Just enqueue a new motion event.  
    7.         MotionEntry* newEntry = mAllocator.obtainMotionEntry(eventTime,  
    8.                 deviceId, source, policyFlags, action, flags, metaState, edgeFlags,  
    9.                 xPrecision, yPrecision, downTime,  
    10.                 pointerCount, pointerIds, pointerCoords);  
    11.   
    12.         needWake = enqueueInboundEventLocked(newEntry);  
    13. }  
     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);  
    1. needWake = enqueueInboundEventLocked(newEntry);  
     needWake = enqueueInboundEventLocked(newEntry);

     

    Cpp代码 复制代码  收藏代码
    1. bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {   
    2.     bool needWake = mInboundQueue.isEmpty();   
    3.     mInboundQueue.enqueueAtTail(entry);   
    4.   
    5.     switch (entry->type) {   
    6.     case EventEntry::TYPE_KEY: {   
    7.         KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);   
    8.         if (isAppSwitchKeyEventLocked(keyEntry)) {   
    9.             if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {   
    10.                 mAppSwitchSawKeyDown = true;   
    11.             } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {   
    12.                 if (mAppSwitchSawKeyDown) {   
    13. #if DEBUG_APP_SWITCH   
    14.                     LOGD("App switch is pending!");   
    15. #endif   
    16.                     mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;   
    17.                     mAppSwitchSawKeyDown = false;   
    18.                     needWake = true;   
    19.                 }   
    20.             }   
    21.         }   
    22.         break;   
    23.     }   
    24.     }   
    25.   
    26.     return needWake;   
    27. }  
    1. bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {  
    2.     bool needWake = mInboundQueue.isEmpty();  
    3.     mInboundQueue.enqueueAtTail(entry);  
    4.   
    5.     switch (entry->type) {  
    6.     case EventEntry::TYPE_KEY: {  
    7.         KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);  
    8.         if (isAppSwitchKeyEventLocked(keyEntry)) {  
    9.             if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {  
    10.                 mAppSwitchSawKeyDown = true;  
    11.             } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {  
    12.                 if (mAppSwitchSawKeyDown) {  
    13. #if DEBUG_APP_SWITCH  
    14.                     LOGD("App switch is pending!");  
    15. #endif  
    16.                     mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;  
    17.                     mAppSwitchSawKeyDown = false;  
    18.                     needWake = true;  
    19.                 }  
    20.             }  
    21.         }  
    22.         break;  
    23.     }  
    24.     }  
    25.   
    26.     return needWake;  
    27. }  
    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插入到队列就完成了。  
    1. mInboundQueue正是上面所说的队列。到此为止,从InputReader插入到队列就完成了。  
    mInboundQueue正是上面所说的队列。到此为止,从InputReader插入到队列就完成了。

     那么InputDispatcher又是如何从队列中取出来的呢?累了。

      InputDiapather的

    Cpp代码 复制代码  收藏代码
    1. dispatchOnce  
    1. dispatchOnce  
    dispatchOnce

    方法如下:

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

    Cpp代码 复制代码  收藏代码
    1.     mLooper->pollOnce(timeoutMillis);(这个方法在有个回调,与事件有关的是【管道设备的文件描述符】。   
    2.   具体机制在后面讲。这个东西实际上是个跨进程的信号。发送给了Android的用户进程的JNI,又通过JNI调用InputQueue的的   
    3. 静态方法如:dispatchMotionEvent。后面回提到dispatchMotionEvent才是Android用户进程的事件入口函数。)   
    4. )  
    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.   
    13. }  
    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.   
    13. }  
    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  
    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 = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
                    motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState,
                    xOffset, yOffset,
                    motionEntry->xPrecision, motionEntry->yPrecision,
                    motionEntry->downTime, firstMotionSample->eventTime,
                    motionEntry->pointerCount, motionEntry->pointerIds,
                    firstMotionSample->pointerCoords);

     

    至此,InputDisapatcher也结束了。

    既然发布出去,必然有订阅者:在InputTransport.cpp中

    Java代码 复制代码  收藏代码
    1. status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {   
    2. #if DEBUG_TRANSPORT_ACTIONS   
    3.     LOGD("channel '%s' consumer ~ consume",   
    4.             mChannel->getName().string());   
    5. #endif   
    6.   
    7.     *outEvent = NULL;   
    8.   
    9.     int ashmemFd = mChannel->getAshmemFd();   
    10.     int result = ashmem_pin_region(ashmemFd, 00);   
    11.     if (result != ASHMEM_NOT_PURGED) {   
    12.         if (result == ASHMEM_WAS_PURGED) {   
    13.             LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged "  
    14.                     "which probably indicates that the publisher and consumer are out of sync.",   
    15.                     mChannel->getName().string(), result, ashmemFd);   
    16.             return INVALID_OPERATION;   
    17.         }   
    18.   
    19.         LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",   
    20.                 mChannel->getName().string(), result, ashmemFd);   
    21.         return UNKNOWN_ERROR;   
    22.     }   
    23.   
    24.     if (mSharedMessage->consumed) {   
    25.         LOGE("channel '%s' consumer ~ The current message has already been consumed.",   
    26.                 mChannel->getName().string());   
    27.         return INVALID_OPERATION;   
    28.     }   
    29.   
    30.     // Acquire but *never release* the semaphore.  Contention on the semaphore is used to signal  
    31.     // to the publisher that the message has been consumed (or is in the process of being  
    32.     // consumed).  Eventually the publisher will reinitialize the semaphore for the next message.  
    33.     result = sem_wait(& mSharedMessage->semaphore);   
    34.     if (result < 0) {   
    35.         LOGE("channel '%s' consumer ~ Error %d in sem_wait.",   
    36.                 mChannel->getName().string(), errno);   
    37.         return UNKNOWN_ERROR;   
    38.     }   
    39.   
    40.     mSharedMessage->consumed = true;   
    41.   
    42.     switch (mSharedMessage->type) {   
    43.     case AINPUT_EVENT_TYPE_KEY: {   
    44.         KeyEvent* keyEvent = factory->createKeyEvent();   
    45.         if (! keyEvent) return NO_MEMORY;   
    46.   
    47.         populateKeyEvent(keyEvent);   
    48.   
    49.         *outEvent = keyEvent;   
    50.         break;   
    51.     }   
    52.   
    53.     case AINPUT_EVENT_TYPE_MOTION: {   
    54.         MotionEvent* motionEvent = factory->createMotionEvent();   
    55.         if (! motionEvent) return NO_MEMORY;   
    56.   
    57.         populateMotionEvent(motionEvent);   
    58.   
    59.         *outEvent = motionEvent;   
    60.         break;   
    61.     }   
    62.   
    63.     default:   
    64.         LOGE("channel '%s' consumer ~ Received message of unknown type %d",   
    65.                 mChannel->getName().string(), mSharedMessage->type);   
    66.         return UNKNOWN_ERROR;   
    67.     }   
    68.   
    69.     return OK;   
    70. }  
    1. status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {  
    2. #if DEBUG_TRANSPORT_ACTIONS  
    3.     LOGD("channel '%s' consumer ~ consume",  
    4.             mChannel->getName().string());  
    5. #endif  
    6.   
    7.     *outEvent = NULL;  
    8.   
    9.     int ashmemFd = mChannel->getAshmemFd();  
    10.     int result = ashmem_pin_region(ashmemFd, 00);  
    11.     if (result != ASHMEM_NOT_PURGED) {  
    12.         if (result == ASHMEM_WAS_PURGED) {  
    13.             LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged "  
    14.                     "which probably indicates that the publisher and consumer are out of sync.",  
    15.                     mChannel->getName().string(), result, ashmemFd);  
    16.             return INVALID_OPERATION;  
    17.         }  
    18.   
    19.         LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",  
    20.                 mChannel->getName().string(), result, ashmemFd);  
    21.         return UNKNOWN_ERROR;  
    22.     }  
    23.   
    24.     if (mSharedMessage->consumed) {  
    25.         LOGE("channel '%s' consumer ~ The current message has already been consumed.",  
    26.                 mChannel->getName().string());  
    27.         return INVALID_OPERATION;  
    28.     }  
    29.   
    30.     // Acquire but *never release* the semaphore.  Contention on the semaphore is used to signal  
    31.     // to the publisher that the message has been consumed (or is in the process of being  
    32.     // consumed).  Eventually the publisher will reinitialize the semaphore for the next message.  
    33.     result = sem_wait(& mSharedMessage->semaphore);  
    34.     if (result < 0) {  
    35.         LOGE("channel '%s' consumer ~ Error %d in sem_wait.",  
    36.                 mChannel->getName().string(), errno);  
    37.         return UNKNOWN_ERROR;  
    38.     }  
    39.   
    40.     mSharedMessage->consumed = true;  
    41.   
    42.     switch (mSharedMessage->type) {  
    43.     case AINPUT_EVENT_TYPE_KEY: {  
    44.         KeyEvent* keyEvent = factory->createKeyEvent();  
    45.         if (! keyEvent) return NO_MEMORY;  
    46.   
    47.         populateKeyEvent(keyEvent);  
    48.   
    49.         *outEvent = keyEvent;  
    50.         break;  
    51.     }  
    52.   
    53.     case AINPUT_EVENT_TYPE_MOTION: {  
    54.         MotionEvent* motionEvent = factory->createMotionEvent();  
    55.         if (! motionEvent) return NO_MEMORY;  
    56.   
    57.         populateMotionEvent(motionEvent);  
    58.   
    59.         *outEvent = motionEvent;  
    60.         break;  
    61.     }  
    62.   
    63.     default:  
    64.         LOGE("channel '%s' consumer ~ Received message of unknown type %d",  
    65.                 mChannel->getName().string(), mSharedMessage->type);  
    66.         return UNKNOWN_ERROR;  
    67.     }  
    68.   
    69.     return OK;  
    70. }  
    status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
    #if DEBUG_TRANSPORT_ACTIONS
        LOGD("channel '%s' consumer ~ consume",
                mChannel->getName().string());
    #endif
    
        *outEvent = NULL;
    
        int ashmemFd = mChannel->getAshmemFd();
        int result = ashmem_pin_region(ashmemFd, 0, 0);
        if (result != ASHMEM_NOT_PURGED) {
            if (result == ASHMEM_WAS_PURGED) {
                LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged "
                        "which probably indicates that the publisher and consumer are out of sync.",
                        mChannel->getName().string(), result, ashmemFd);
                return INVALID_OPERATION;
            }
    
            LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",
                    mChannel->getName().string(), result, ashmemFd);
            return UNKNOWN_ERROR;
        }
    
        if (mSharedMessage->consumed) {
            LOGE("channel '%s' consumer ~ The current message has already been consumed.",
                    mChannel->getName().string());
            return INVALID_OPERATION;
        }
    
        // Acquire but *never release* the semaphore.  Contention on the semaphore is used to signal
        // to the publisher that the message has been consumed (or is in the process of being
        // consumed).  Eventually the publisher will reinitialize the semaphore for the next message.
        result = sem_wait(& mSharedMessage->semaphore);
        if (result < 0) {
            LOGE("channel '%s' consumer ~ Error %d in sem_wait.",
                    mChannel->getName().string(), errno);
            return UNKNOWN_ERROR;
        }
    
        mSharedMessage->consumed = true;
    
        switch (mSharedMessage->type) {
        case AINPUT_EVENT_TYPE_KEY: {
            KeyEvent* keyEvent = factory->createKeyEvent();
            if (! keyEvent) return NO_MEMORY;
    
            populateKeyEvent(keyEvent);
    
            *outEvent = keyEvent;
            break;
        }
    
        case AINPUT_EVENT_TYPE_MOTION: {
            MotionEvent* motionEvent = factory->createMotionEvent();
            if (! motionEvent) return NO_MEMORY;
    
            populateMotionEvent(motionEvent);
    
            *outEvent = motionEvent;
            break;
        }
    
        default:
            LOGE("channel '%s' consumer ~ Received message of unknown type %d",
                    mChannel->getName().string(), mSharedMessage->type);
            return UNKNOWN_ERROR;
        }
    
        return OK;
    }
    

     也许我们最关心的是如何订阅的,不得不取看一下JNI的代码,文件android_view_InputQueue.cpp

     聚焦到这里

     

    Cpp代码 复制代码  收藏代码
    1. status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChannelObj,   
    2.         jobject inputHandlerObj, jobject messageQueueObj) {   
    3.     sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,   
    4.             inputChannelObj);   
    5.     if (inputChannel == NULL) {   
    6.         LOGW("Input channel is not initialized.");   
    7.         return BAD_VALUE;   
    8.     }   
    9.   
    10. #if DEBUG_REGISTRATION   
    11.     LOGD("channel '%s' - Registered", inputChannel->getName().string());   
    12. #endif   
    13.   
    14.     sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);   
    15.   
    16.     { // acquire lock   
    17.         AutoMutex _l(mLock);   
    18.   
    19.         if (getConnectionIndex(inputChannel) >= 0) {   
    20.             LOGW("Attempted to register already registered input channel '%s'",   
    21.                     inputChannel->getName().string());   
    22.             return BAD_VALUE;   
    23.         }   
    24.   
    25.         uint16_t connectionId = mNextConnectionId++;   
    26.         sp<Connection> connection = new Connection(connectionId, inputChannel, looper);   
    27.         status_t result = connection->inputConsumer.initialize();   
    28.         if (result) {   
    29.             LOGW("Failed to initialize input consumer for input channel '%s', status=%d",   
    30.                     inputChannel->getName().string(), result);   
    31.             return result;   
    32.         }   
    33.   
    34.         connection->inputHandlerObjGlobal = env->NewGlobalRef(inputHandlerObj);   
    35.   
    36.         int32_t receiveFd = inputChannel->getReceivePipeFd();   
    37.         mConnectionsByReceiveFd.add(receiveFd, connection);   
    38.   
    39.         looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);   
    40.     } // release lock   
    41.   
    42.     android_view_InputChannel_setDisposeCallback(env, inputChannelObj,   
    43.             handleInputChannelDisposed, this);   
    44.     return OK;   
    45. }  
    1. status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChannelObj,  
    2.         jobject inputHandlerObj, jobject messageQueueObj) {  
    3.     sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,  
    4.             inputChannelObj);  
    5.     if (inputChannel == NULL) {  
    6.         LOGW("Input channel is not initialized.");  
    7.         return BAD_VALUE;  
    8.     }  
    9.   
    10. #if DEBUG_REGISTRATION  
    11.     LOGD("channel '%s' - Registered", inputChannel->getName().string());  
    12. #endif  
    13.   
    14.     sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);  
    15.   
    16.     { // acquire lock  
    17.         AutoMutex _l(mLock);  
    18.   
    19.         if (getConnectionIndex(inputChannel) >= 0) {  
    20.             LOGW("Attempted to register already registered input channel '%s'",  
    21.                     inputChannel->getName().string());  
    22.             return BAD_VALUE;  
    23.         }  
    24.   
    25.         uint16_t connectionId = mNextConnectionId++;  
    26.         sp<Connection> connection = new Connection(connectionId, inputChannel, looper);  
    27.         status_t result = connection->inputConsumer.initialize();  
    28.         if (result) {  
    29.             LOGW("Failed to initialize input consumer for input channel '%s', status=%d",  
    30.                     inputChannel->getName().string(), result);  
    31.             return result;  
    32.         }  
    33.   
    34.         connection->inputHandlerObjGlobal = env->NewGlobalRef(inputHandlerObj);  
    35.   
    36.         int32_t receiveFd = inputChannel->getReceivePipeFd();  
    37.         mConnectionsByReceiveFd.add(receiveFd, connection);  
    38.   
    39.         looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);  
    40.     } // release lock  
    41.   
    42.     android_view_InputChannel_setDisposeCallback(env, inputChannelObj,  
    43.             handleInputChannelDisposed, this);  
    44.     return OK;  
    45. }  
    status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChannelObj,
            jobject inputHandlerObj, jobject messageQueueObj) {
        sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
                inputChannelObj);
        if (inputChannel == NULL) {
            LOGW("Input channel is not initialized.");
            return BAD_VALUE;
        }
    
    #if DEBUG_REGISTRATION
        LOGD("channel '%s' - Registered", inputChannel->getName().string());
    #endif
    
        sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
    
        { // acquire lock
            AutoMutex _l(mLock);
    
            if (getConnectionIndex(inputChannel) >= 0) {
                LOGW("Attempted to register already registered input channel '%s'",
                        inputChannel->getName().string());
                return BAD_VALUE;
            }
    
            uint16_t connectionId = mNextConnectionId++;
            sp<Connection> connection = new Connection(connectionId, inputChannel, looper);
            status_t result = connection->inputConsumer.initialize();
            if (result) {
                LOGW("Failed to initialize input consumer for input channel '%s', status=%d",
                        inputChannel->getName().string(), result);
                return result;
            }
    
            connection->inputHandlerObjGlobal = env->NewGlobalRef(inputHandlerObj);
    
            int32_t receiveFd = inputChannel->getReceivePipeFd();
            mConnectionsByReceiveFd.add(receiveFd, connection);
    
            looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
        } // release lock
    
        android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
                handleInputChannelDisposed, this);
        return OK;
    }
     

     

      也许更想知道的是消息队列在什么地方,进入InputQueue.java来看

     

    Java代码 复制代码  收藏代码
    1. public static void registerInputChannel(InputChannel inputChannel, InputHandler inputHandler,   
    2.         MessageQueue messageQueue) {   
    3.     if (inputChannel == null) {   
    4.         throw new IllegalArgumentException("inputChannel must not be null");   
    5.     }   
    6.     if (inputHandler == null) {   
    7.         throw new IllegalArgumentException("inputHandler must not be null");   
    8.     }   
    9.     if (messageQueue == null) {   
    10.         throw new IllegalArgumentException("messageQueue must not be null");   
    11.     }   
    12.        
    13.     synchronized (sLock) {   
    14.         if (DEBUG) {   
    15.             Slog.d(TAG, "Registering input channel '" + inputChannel + "'");   
    16.         }   
    17.            
    18.         nativeRegisterInputChannel(inputChannel, inputHandler, messageQueue);   
    19.     }   
    20. }   
    1. public static void registerInputChannel(InputChannel inputChannel, InputHandler inputHandler,  
    2.         MessageQueue messageQueue) {  
    3.     if (inputChannel == null) {  
    4.         throw new IllegalArgumentException("inputChannel must not be null");  
    5.     }  
    6.     if (inputHandler == null) {  
    7.         throw new IllegalArgumentException("inputHandler must not be null");  
    8.     }  
    9.     if (messageQueue == null) {  
    10.         throw new IllegalArgumentException("messageQueue must not be null");  
    11.     }  
    12.       
    13.     synchronized (sLock) {  
    14.         if (DEBUG) {  
    15.             Slog.d(TAG, "Registering input channel '" + inputChannel + "'");  
    16.         }  
    17.           
    18.         nativeRegisterInputChannel(inputChannel, inputHandler, messageQueue);  
    19.     }  
    20. }  
        public static void registerInputChannel(InputChannel inputChannel, InputHandler inputHandler,
                MessageQueue messageQueue) {
            if (inputChannel == null) {
                throw new IllegalArgumentException("inputChannel must not be null");
            }
            if (inputHandler == null) {
                throw new IllegalArgumentException("inputHandler must not be null");
            }
            if (messageQueue == null) {
                throw new IllegalArgumentException("messageQueue must not be null");
            }
            
            synchronized (sLock) {
                if (DEBUG) {
                    Slog.d(TAG, "Registering input channel '" + inputChannel + "'");
                }
                
                nativeRegisterInputChannel(inputChannel, inputHandler, messageQueue);
            }
        }
        
    
     

    在ViewRoot.java中有这么几行

     

    Cpp代码 复制代码  收藏代码
    1. InputQueue.registerInputChannel(mInputChannel, mInputHandler,   
    2.         Looper.myQueue());  
    1. InputQueue.registerInputChannel(mInputChannel, mInputHandler,  
    2.         Looper.myQueue());  
                        InputQueue.registerInputChannel(mInputChannel, mInputHandler,
                                Looper.myQueue());

     完毕。

    这才牵涉到管道的问题,哪个Java中的Channel对应的正是linux系统的管道。有了管道,才能通过 跨进程方式回调回来,为什么是这个入口,上面进行了解释。具体参照INputQUEUE这个java类的JNI方法

    int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data)

    这个方法被InputQueue的RegisterInputChannel注册给了系统.系统通过回调,回调的是这个ALOOPER_EVENT_INPUT事件。

     

     

    looper就是android中的【用户进程的循环】

    注册的代码为 :

      looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);

    回调的java函数为

    Java代码 复制代码  收藏代码
    1.        
    2. 回调的java代码的方法入口为:InputQueue.java中的。   
    3.   
    4. @SuppressWarnings("unused")   
    5.     private static void dispatchMotionEvent(InputHandler inputHandler,   
    6.             MotionEvent event, long finishedToken) {   
    7.         Runnable finishedCallback = FinishedCallback.obtain(finishedToken);   
    8.         inputHandler.handleMotion(event, finishedCallback);   
    9.     }  
    1.       
    2. 回调的java代码的方法入口为:InputQueue.java中的。  
    3.   
    4. @SuppressWarnings("unused")  
    5.     private static void dispatchMotionEvent(InputHandler inputHandler,  
    6.             MotionEvent event, long finishedToken) {  
    7.         Runnable finishedCallback = FinishedCallback.obtain(finishedToken);  
    8.         inputHandler.handleMotion(event, finishedCallback);  
    9.     }  
        
    回调的java代码的方法入口为:InputQueue.java中的。
    
    @SuppressWarnings("unused")
        private static void dispatchMotionEvent(InputHandler inputHandler,
                MotionEvent event, long finishedToken) {
            Runnable finishedCallback = FinishedCallback.obtain(finishedToken);
            inputHandler.handleMotion(event, finishedCallback);
        }

     这样就回调到了ViewRoot中

  1. dispatchTouches  
dispatchTouches

    只说触摸屏,虚拟键类似,触摸屏调用的是  

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值