Android InputFlinger简单分析(主要分析Touch)

Android InputFlinger简单分析(主要分析Touch)

首先,它有个服务,InputManagerService.

InputManagerService启动

startOtherServices@SystemServer

...
inputManager = new InputManagerService(context);
wm = WindowManagerService.main(context, inputManager,
     mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore);
...
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
...
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
            inputManager.start();
...

看看构造函数:

public InputManagerService(Context context) {
    ...
    mPtr = nativeInit(this, mContext,mHandler.getLooper().getQueue());
    ...
}

这个mPrt之后作为了其他native函数的第一个参数。先看看nativeInit

(位置base/services/core/jni/com_android_server_input_InputManagerService.cpp)

static jlong nativeInit(JNIEnv* env, jclass clazz,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
...
    NativeInputManager* im = new NativeInputManager(contextObj,         serviceObj,messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

简单来理解就是获取java层的消息队列,然后构造了一个NativeInputManager对象,然后返回java层,赋值给mPtr。

前文,startOtherServices@SystemServer中还调用了

inputManager.start();

start()@InputManagerService

...
nativeStart(mPtr);
...

nativeStart:

static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start();
...
}

即用nativeInit中new的NativeInputManager对象调用start函数。

那NativeInputManager是什么呢?

inline sp<InputManager> getInputManager() const { return mInputManager; }

直接去看InputManager调用start函数就好了。

接下来,我们的工作目录就集中到

frameworks/native/services/inputflinger

从InputManager::start开始

...
  status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
...
  result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
...

mDispatcherThread和mReaderThread的run函数,都会去调用threadLoop函数(就当是常识了)。

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

从名字上来看,一个专门去读取input,一个专门去分发input.可是为什么只运行一次(loopOnce)呢?

我们这次主要关注的是touch事件,即MotionEvent.

InputDispatcher.h

struct MotionEntry : EventEntry {

Motion是Event的一种!

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);

这几个函数功能应该类似,只不过Event种类不同。

在InputDispatcher.cpp中竟然找不到调用。嗯!yes!搜索结果如下:

InputReader.cpp:2551:        getListener()->notifyMotion(&args);
...

getListener@InputReader:

class InputReader : public InputReaderInterface {
...
virtual InputListenerInterface* getListener();

InputDispatcher.h:

class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface
...
class InputDispatcher : public InputDispatcherInterface

回头过去看一下InputManager的构造函数,就都明白了

InputManager::InputManager

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,
        //这个
        const sp<InputListenerInterface>& listener) :
        mContext(this), mEventHub(eventHub), mPolicy(policy),
        mGlobalMetaState(0), mGeneration(1),
        mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {
    mQueuedListener = new QueuedInputListener(listener);

InputListenerInterface* InputReader::ContextImpl::getListener() {
    return mReader->mQueuedListener.get();
}

总的来说就是,notifyMotion函数的调用来自InputReader.读到input之后notify!

InputReader分析

InputReader::loopOnce

//引出一个EventHub,getEvents也非常类似平时在adb shell中使用的命令
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
...
processEventsLocked(mEventBuffer, count);
...

InputReader::processEventsLocked

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {
      ...
        //type不是
        //DEVICE_ADDED,DEVICE_REMOVED,FINISHED_DEVICE_SCAN这三个
        if(type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
      ...
        processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        }
    }
}

我们来看看一个开机加载Touch device的log

V/EventHub( 1691): EventHub::readNotify nfd: 69
V/EventHub( 1691): Opening device: /dev/input/event7
V/EventHub( 1691): Created descriptor: raw=:0000:0000:name:Atmel maXTouch Touchscreen, cooked=37118057a971f33d58dfff27cf9e19bbe8914aca
V/EventHub( 1691): add device 7: /dev/input/event7
V/EventHub( 1691):   bus:        0018
V/EventHub( 1691):   vendor      0000
V/EventHub( 1691):   product     0000
V/EventHub( 1691):   version     0000
V/EventHub( 1691):   name:       "Atmel maXTouch Touchscreen"
V/EventHub( 1691):   location:   "i2c-5-004a/input0"
V/EventHub( 1691):   unique id:  ""
V/EventHub( 1691):   descriptor: "37118057a971f33d58dfff27cf9e19bbe8914aca"
V/EventHub( 1691):   driver:     v1.0.1
D/EventHub( 1691): No input device configuration file found for device 'Atmel maXTouch Touchscreen'.
I/EventHub( 1691): New device: id=7, fd=213, path='/dev/input/event7', name='Atmel maXTouch Touchscreen', classes=0x14, configuration='', keyLayout='', keyCharacterMap='', builtinKeyboard=false, wakeMechanism=EPOLLWAKEUP, usingClockIoctl=true
V/EventHub( 1691): Reporting device opened: id=7, name=/dev/input/event7
V/InputReader( 1691): ZDQ after mEventHub->getEvents
//DEVICE_ADDED = 0x10000000
//这次调用来自mEventHub->getEvents
V/InputReader( 1691): ZDQ InputReader::processEventsLocked type = 10000000
//mode 1:DEVICE_MODE_DIRECT
I/InputReader( 1691): Device reconfigured: id=7, name='Atmel maXTouch Touchscreen', size 1920x720, orientation 0, mode 1, display id 0
I/InputReader( 1691): Device added: id=7, name='Atmel maXTouch Touchscreen', sources=0x00005002
//FINISHED_DEVICE_SCAN = 0x30000000
V/InputReader( 1691): ZDQ InputReader::processEventsLocked type = 30000000

然后,我们来看看一次单点touch事件的log做个预热

getevent -lr /dev/input/event7
EV_ABS       ABS_MT_TRACKING_ID   00000069            
EV_ABS       ABS_MT_POSITION_X    00000608            
EV_ABS       ABS_MT_POSITION_Y    00000075            
EV_KEY       BTN_TOUCH            DOWN                
EV_ABS       ABS_X                00000608            
EV_ABS       ABS_Y                00000075            
EV_SYN       SYN_REPORT           00000000             rate 0
EV_ABS       ABS_MT_TRACKING_ID   ffffffff            
EV_KEY       BTN_TOUCH            UP                  
EV_SYN       SYN_REPORT           00000000             rate 13

第一列是rawEvent->type

第二列是rawEvent->code,在函数MultiTouchMotionAccumulator::process中进行解析

第三列是value

整个event解析出来就是:

1.ABS_MT_TRACKING_ID = 0x00000069,坐标为(0x608,0x75)即
(1544,117)的一个DOWN事件
2.ABS_MT_TRACKING_ID = ffffffff
SYN_REPORT:似乎这个组合(EV_SYN,SYN_REPORT)之后就是下一个事件了
很多的process里头都是这么写的:
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
         sync(rawEvent->when);
}

InputReader::processEventsForDeviceLocked之后

1.InputDevice::process

Process all of the events in order for each mapper.

We cannot simply ask each mapper to process them in bulk because mappers may

have side-effects that must be interleaved. For example, joystick movement events and gamepad button presses are handled by different mappers but they should be dispatched in the order received.

for (size_t i = 0; i < numMappers; i++) {
     InputMapper* mapper = mMappers[i];
     mapper->process(rawEvent);
}

2.mapper->process

class TouchInputMapper : public InputMapper
class SingleTouchInputMapper : public TouchInputMapper
class MultiTouchInputMapper : public TouchInputMapper

MultiTouchInputMapper::process

void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
    TouchInputMapper::process(rawEvent);
    mMultiTouchMotionAccumulator.process(rawEvent);
}

TouchInputMapper::process:

void TouchInputMapper::process(const RawEvent* rawEvent) {
    //应该是给鼠标用的
    //专门负责EV_KEY BTN_LEFT/BTN_MIDDLE/BTN_RIGHT...这种
    mCursorButtonAccumulator.process(rawEvent);
    //EV_REL REL_WHEEL/REL_HWHEEL
    mCursorScrollAccumulator.process(rawEvent);
    //专门负责EV_KEY BTN_TOUCH...
    //触摸事件就这
    //EV_KEY BTN_TOUCH的时候,就一件事:
    //mBtnTouch = rawEvent->value;
    mTouchButtonAccumulator.process(rawEvent);
    //开始报点
    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
        sync(rawEvent->when);
    }
    ...
}

TouchInputMapper::sync

...
// Sync touch state.
bool havePointerIds = true;
//mCurrentRawPointerData会在这里被清掉
mCurrentRawPointerData.clear();
//纯虚函数
syncTouch(when, &havePointerIds);
...
//加工点的数据
cookPointerData();

由于syncTouch是纯虚函数,所以,syncTouch的实现在SingleTouchInputMapper,MultiTouchInputMapper中都有.

那这个地方怎么调用呢?

前面看过的一次开机log中

I/EventHub( 1691): New device: id=7, fd=213, path='/dev/input/event7', name='Atmel maXTouch Touchscreen', classes=0x14, configuration='', keyLayout='', keyCharacterMap='', builtinKeyboard=false, wakeMechanism=EPOLLWAKEUP, usingClockIoctl=true

可以看到classes=0x14

EventHub.h

/* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
INPUT_DEVICE_CLASS_TOUCH         = 0x00000004,
/* The input device is a multi-touch touchscreen. */
INPUT_DEVICE_CLASS_TOUCH_MT      = 0x00000010,

而InputReader::addDeviceLocked中调用了createDeviceLocked

InputReader::createDeviceLocked:

// Touchscreens and touchpad devices.
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
    device->addMapper(new MultiTouchInputMapper(device));
} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
    device->addMapper(new SingleTouchInputMapper(device));
}

也就是说在这种情况下,SingleTouchInputMapper这个类基本是用不上的.

那前面的疑问就没了,调用的就是

//这个函数通过mMultiTouchMotionAccumulator(多点触控累加器?什么鬼?)给mCurrentRawPointerData赋了值!
void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
  //Slot?槽?
    size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();//configure的时候赋值,这里是16
    size_t outCount = 0;
    for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
        const MultiTouchMotionAccumulator::Slot* inSlot =
                mMultiTouchMotionAccumulator.getSlot(inIndex);
      if (!inSlot->isInUse()) {
        //16个slot中,not inUse的全在这continue!只有inUse的才会赋值给mCurrentRawPointerData
        continue;
      }
    ...
        RawPointerData::Pointer& outPointer =                         
            mCurrentRawPointerData.pointers[outCount];
        outPointer.x = inSlot->getX();
        outPointer.y = inSlot->getY();
    ...
        outCount += 1;
    }
...
}

inSlot->isInUse()怎么判定?

void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
    ...
        Slot* slot = &mSlots[mCurrentSlot];
        case ABS_MT_POSITION_X:
                slot->mInUse = true;
                slot->mAbsMTPositionX = rawEvent->value;
                break;
            case ABS_MT_POSITION_Y:
                slot->mInUse = true;
    ...
}

可以说,主要由mCurrentSlot来决定!16个Slot中,有一个被选中,成为mCurrentSlot,这个对应的slot就成了inUse!

那么什么时候取消mInUse呢?就是驱动上报这样的事件:

EV_ABS ABS_MT_TRACKING_ID ffffffff

不信你看

case ABS_MT_TRACKING_ID:
                if (mUsingSlotsProtocol && rawEvent->value < 0) {
                    // The slot is no longer in use but it retains its previous contents,
                    // which may be reused for subsequent touches.
                    //(翻译下上面的英文)这个slot不再inUse了,但是它保留它之前的(那些可以被随后的touches重新使用)内容
                    slot->mInUse = false;
                } else {
                    slot->mInUse = true;
                    slot->mAbsMTTrackingId = rawEvent->value;
                }

前面说到,给mCurrentRawPointerData赋值的主体主要是:

mMultiTouchMotionAccumulator.getSlot(inIndex);

inline const Slot* getSlot(size_t index) const { return &mSlots[index]; }

赋值的地方只有一个:

void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
    if (rawEvent->type == EV_ABS) {
    ...
        switch (rawEvent->code) {
            case ABS_MT_POSITION_X:
                slot->mInUse = true;
                //这么取值
                //inline int32_t getX() const { return mAbsMTPositionX; }
                slot->mAbsMTPositionX = rawEvent->value;
                break;
        ...
            case ABS_MT_TRACKING_ID:
                if (mUsingSlotsProtocol && rawEvent->value < 0) {
                    // The slot is no longer in use but it retains its previous contents,
                    // which may be reused for subsequent touches.
                    slot->mInUse = false;
                } else {
                    slot->mInUse = true;
                    slot->mAbsMTTrackingId = rawEvent->value;
                }
            break;
        ...
        }
    } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
        // MultiTouch Sync: The driver has returned all data for *one* of the       pointers.
        mCurrentSlot += 1;
    }
}

MultiTouchMotionAccumulator::process

if (rawEvent->type == EV_ABS) {
    bool newSlot = false;
    //log来看,这个值为true
    if (mUsingSlotsProtocol) {
         if (rawEvent->code == ABS_MT_SLOT) {
                //底层会上报多个值,一跟手指0,两根0,1...
              mCurrentSlot = rawEvent->value;
              newSlot = true;
          }
    } else if (mCurrentSlot < 0) {
          mCurrentSlot = 0;
    }
//开始解析rawEvent->code
Slot* slot = &mSlots[mCurrentSlot];
switch (rawEvent->code) {
...
case ABS_MT_POSITION_X:
    slot->mInUse = true;
    slot->mAbsMTPositionX = rawEvent->value;
    break;
...
}

mUsingSlotsProtocol在这里就是B协议,详细情况可以参考这篇文章:

http://www.cnblogs.com/ljf181275034/articles/3343222.html

接着看看前面说到的加工点数据的cookPointerData

void TouchInputMapper::cookPointerData() {
    uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
    ...
      // Walk through the the active pointers and map device coordinates onto
      // surface coordinates and adjust for display orientation.
      for (uint32_t i = 0; i < currentPointerCount; i++) {
          const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i];
            //接下来就是从in中去解析
            //Size
            //Pressure
            //Tilt and Orientation
            //Distance
            //Coverage
            //Adjust X, Y, and coverage coords for surface orientation.(根据surface                   orientation调整x,y坐标)
            // Write output coords.
            PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i];
            out.clear();
            out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
            out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
            ...
            // Write output properties.
            // Write id index.
      }
    ...
}   

cookPointerData把mCurrentRawPointerData加工成了mCurrentCookedPointerData!

再之后就是dispatchTouches(when, policyFlags)

void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
    BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits;
    BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits;
    ...
    if (currentIdBits == lastIdBits) {
        //没有pointer id变化,所以,这是一个move事件
        //注意是所有点(xxxxBits用bit位包含所有点的id)
        ...
        dispatchMotion(when, policyFlags, mSource,
                    AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
                    AMOTION_EVENT_EDGE_FLAG_NONE,
                    mCurrentCookedPointerData.pointerProperties,
                    mCurrentCookedPointerData.pointerCoords,
                    mCurrentCookedPointerData.idToIndex,
                    currentIdBits, -1,
                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
        ...
    } else {
      //如果lastIdBits == currentIdBits,upIdBits就是0
      //但是这个else是!=,所以这个结果就是把少掉的点(即已经up的点)找出来
      BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
      //同理,这个是多出来的点(down)
      BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
      //
      BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
      //根据不同的情况,分别做
      //AMOTION_EVENT_ACTION_POINTER_UP
      //AMOTION_EVENT_ACTION_MOVE
      //AMOTION_EVENT_ACTION_POINTER_DOWN
      ...
        dispatchMotion...
    }

TouchInputMapper::dispatchMotion:

...
 //0x5(DOWN)的ACTION经过这处理,变成0x105
 //同理,0x6变成0x106
if (changedId >= 0 && id == uint32_t(changedId)) {
    action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
...

NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
            action, flags, metaState, buttonState, edgeFlags,
            mViewport.displayId, pointerCount, pointerProperties,                   pointerCoords,xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
...

简单总结下整个过程:

1.eventhub上报:

(多点的时候)EV_ABS ABS_MT_SLOT 00000000

if (rawEvent->code == ABS_MT_SLOT) {
     mCurrentSlot = rawEvent->value;//设置当前slot为0
     newSlot = true;
}

EV_ABS ABS_MT_TRACKING_ID id

调用MultiTouchMotionAccumulator::process

mSlots[0]->mAbsMTTrackingId = id//给mSlots[mCurrentSlot]赋值

2.EV_ABS ABS_MT_POSITION_X x

调用MultiTouchMotionAccumulator::process

mSlots[0]->mAbsMTPositionX = x//给mSlot[mCurrentSlot]s赋值

3.EV_ABS ABS_MT_POSITION_Y y

调用MultiTouchMotionAccumulator::process

mSlots[0]->mAbsMTPositionY = y//给mSlots[mCurrentSlot]赋值

4.EV_SYN SYN_REPORT

TouchInputMapper::process
    TouchInputMapper::sync
        (1)MultiTouchInputMapper::syncTouch
        对mCurrentRawPointerData.pointers[0]进行赋值.
        (2)MultiTouchInputMapper::cookPointerData();
        加工mCurrentRawPointerData.pointers[0]数据
        (3)dispatchTouches
            dispatchMotion
                getListener()->notifyMotion(&args);

5.EV_ABS ABS_MT_TRACKING_ID ffffffff

调用MultiTouchMotionAccumulator::process

mSlots[0]->mAbsMTTrackingId = ffffffff(超出范围,所以是-1)

所以这里就

//打日志得到的
//mUsingSlotsProtocol = 1,rawEvent->value = -1
if (mUsingSlotsProtocol && rawEvent->value < 0) {
    slot->mInUse = false;
}
进而isInUse函数就会返回false啦!

6.EV_SYN SYN_REPORT 00000000

TouchInputMapper::process
    TouchInputMapper::sync
        (1)MultiTouchInputMapper::syncTouch
            走入
            if (!inSlot->isInUse()) {
                continue;
            }
        (2)cookPointerData这里什么都没干
        (3)dispatchTouches
            dispatchMotion
                getListener()->notifyMotion(&args);

InputDispatcher分析

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
    ...
    needWake = enqueueInboundEventLocked(newEntry);//是否需要唤醒
    ...
    if (needWake) {
        //
        mLooper->wake();//如果需要唤醒,唤醒之,具体一会儿说
    }
    ...
}

我们先看看needWake的判定

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    ...
      //mInboundQueue(入站队列)为空的时候,需要唤醒
        bool needWake = mInboundQueue.isEmpty();
        mInboundQueue.enqueueAtTail(entry);
    ...
        switch (entry->type) {
        case EventEntry::TYPE_KEY: {
            //notifyKey走这一支
        }
    ...
        case EventEntry::TYPE_MOTION: {
          ...
            sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
            if (touchedWindowHandle != NULL
                    && touchedWindowHandle->inputApplicationHandle
                            != mInputTargetWaitApplicationHandle) {
                // User touched a different application than the one we are waiting on.
                // Flag the event, and start pruning the input queue.
                mNextUnblockedEvent = motionEntry;
                needWake = true;
            }
          ...                 
        }
    ...
}

简单总结下就是,之前在休眠,mInboundQueue为空的时候需要唤醒.用户触摸另一个application时候需要唤醒.

那前面说到,需要唤醒的时候,会调用mLooper->wake()

这之后的过程,连猜带Google,得出的结论就是会执行

bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;
}

void InputDispatcher::dispatchOnce() {
  ...
    // Run a dispatch loop if there are no pending commands.
    // The dispatch loop might enqueue commands to run afterwards.
    if (!haveCommandsLocked()) {
        dispatchOnceInnerLocked(&nextWakeupTime);
    }
  ...
    //总之参数就是一个很大很大的超时时间
    mLooper->pollOnce(timeoutMillis);
}

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    ...
      case EventEntry::TYPE_MOTION: {
            done = dispatchMotionLocked(currentTime, typedEntry,
                &dropReason, nextWakeupTime);
      }
    ...
}

bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
    ...
        bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;

        // Identify targets.
        Vector<InputTarget> inputTargets;
        if (isPointerEvent) {
        // Pointer event.  (eg. touchscreen)
        //找到目标窗口
         //这个方法很复杂,先这样吧
        injectionResult = findTouchedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
        }
    ...
        //分发MotionEvent啦!
        dispatchEventLocked(currentTime, entry, inputTargets);
}

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
    ...
        //戳用户Activity?暂时不知道是干嘛的
        pokeUserActivityLocked(eventEntry);
        //
        for (size_t i = 0; i < inputTargets.size(); i++) {
            const InputTarget& inputTarget = inputTargets.itemAt(i);
         ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
            if (connectionIndex >= 0) {
                //mConnectionsByFd在InputDispatcher::registerInputChannel中被关联
                //mConnectionsByFd.add(fd, connection);
                sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
                prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
            }
        }
    ...
}

InputDispatcher::registerInputChannel关联connection和fd的事情以后再谈,我们先继续看

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
    ...
    // Not splitting.  Enqueue dispatch entries for the event as is.
    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
    //这时候已经变成outbound了
    bool wasEmpty = connection->outboundQueue.isEmpty();
    // Enqueue dispatch entries for the requested modes.
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
    ...
    // If the outbound queue was previously empty, start the dispatch cycle going.
    //之前空,后来不空
    if (wasEmpty && !connection->outboundQueue.isEmpty()) {
        startDispatchCycleLocked(currentTime, connection);
    }
}

void InputDispatcher::enqueueDispatchEntryLocked(
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
        int32_t dispatchMode) {
    // This is a new event.
    // Enqueue a new dispatch entry onto the outbound queue for this connection.
    //构造一个dispatchEntry
    DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
            inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
            inputTarget->scaleFactor);
  ...
    case EventEntry::TYPE_MOTION: {
        //对dispatchEntry做一些处理
    }
  ...
    //将dispatchEntry加到outboundQueue的队尾
    connection->outboundQueue.enqueueAtTail(dispatchEntry);
}

enqueueDispatchEntriesLocked中,connection->outboundQueue不为空的时候就会调用

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) {
    while (connection->status == Connection::STATUS_NORMAL
            && !connection->outboundQueue.isEmpty()) {
        ...
          case EventEntry::TYPE_KEY:
            status = connection->inputPublisher.publishKeyEvent(...
        ...
          // Publish the motion event.
          case EventEntry::TYPE_MOTION:                                             
            status = connection->inputPublisher.publishMotionEvent(
        ...
          //出站dispatchEntry
          connection->outboundQueue.dequeue(dispatchEntry);
        ...
          //将dispatchEntry加入connection->waitQueue
          connection->waitQueue.enqueueAtTail(dispatchEntry);
        ...
    }
}

publishKeyEvent和publishMotionEvent就进入InputChannel

(位于frameworks/native/libs/input/InputTransport.cpp)里啦!

InputDispathcher的部分就分析完了!

java层其他

1.View implements

KeyEvent.Callback

onKeyDown
onKeyLongPress
onKeyUp
等接口

KeyEvent extends InputEvent

按键输入是所有输入的一个子集!可以理解

2.MotionEvent

(dispatchTouchEvent的参数)

touch事件的细节

MotionEvent KeyEvent extends InputEvent

基本都调用的native方法

3.调用堆栈

java层:

jni调用上来的?:

ViewRootImpl.java:WindowInputEventReceiver:

onInputEvent

ViewRootImpl.java:enqueueInputEvent

ViewRootImpl.java:processPointerEvent

->View.java:dispatchPointerEvent

->View.java:dispathTouchEvent

->listenerInfo.mOnTouchListener.onTouch

InputEventReceiver.java中

像dispatchInputEvent()这种函数是Called from native code的

每一次触控,会被native层调用,然后往上传递事件,比如一次点击事件的down,move,up事件。我简直觉得这里是最重要的关口之一!

回调点:

android_view_InputEventReceiver.cpp:

NativeInputEventReceiver::consumeEvents

env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);

猜你喜欢

转载自blog.csdn.net/bberdong/article/details/78626366
今日推荐