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

来源:互联网 发布:网络女歌手歌曲大全 编辑:程序博客网 时间:2024/06/02 05:19

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: 69V/EventHub( 1691): Opening device: /dev/input/event7V/EventHub( 1691): Created descriptor: raw=:0000:0000:name:Atmel maXTouch Touchscreen, cooked=37118057a971f33d58dfff27cf9e19bbe8914acaV/EventHub( 1691): add device 7: /dev/input/event7V/EventHub( 1691):   bus:        0018V/EventHub( 1691):   vendor      0000V/EventHub( 1691):   product     0000V/EventHub( 1691):   version     0000V/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.1D/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=trueV/EventHub( 1691): Reporting device opened: id=7, name=/dev/input/event7V/InputReader( 1691): ZDQ after mEventHub->getEvents//DEVICE_ADDED = 0x10000000//这次调用来自mEventHub->getEventsV/InputReader( 1691): ZDQ InputReader::processEventsLocked type = 10000000//mode 1:DEVICE_MODE_DIRECTI/InputReader( 1691): Device reconfigured: id=7, name='Atmel maXTouch Touchscreen', size 1920x720, orientation 0, mode 1, display id 0I/InputReader( 1691): Device added: id=7, name='Atmel maXTouch Touchscreen', sources=0x00005002//FINISHED_DEVICE_SCAN = 0x30000000V/InputReader( 1691): ZDQ InputReader::processEventsLocked type = 30000000

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

getevent -lr /dev/input/event7EV_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 0EV_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 = ffffffffSYN_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 InputMapperclass SingleTouchInputMapper : public TouchInputMapperclass 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->codeSlot* 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变成0x106if (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 = -1if (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

onKeyDownonKeyLongPressonKeyUp等接口

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);
原创粉丝点击