Android 4.2 Input 流程分析

1. 前言

  Android中管理Input的两个主要相关角色, 一是WindowManagerService, 一是跟View相关的ViewRootImpl. 基本原理方向从2.3到目前的4.2都一样,在 Android app一启动之后, ViewRootImpl 就会先跟 WindowManagerService 建立inputChannel, 一旦 WindowManagerService 有收到 event 就会经由 inputChannel 通知 ViewRootImpl 去共享内存中抓取 event. 虽然方向一样, 但是里面的架构有改,目前最新的版本是android 4.2, 所以以下的输入事件处理程序是以4.2来说明, 以后的版本一定会再更改.到时候在研究.

2. 事件处理程序

  2.1 建立 InputChannel

  Android Activity 一启动时会先利用 setContentView 来设置画面, 最后会由 ViewRootImpl 中的 setView函数来做画面的设置, setContentView 跟 setView 有甚么关系, 并不是这里的重点. 那是属于Surface 的范围. 接下来就来看 setView 函数的实作, 跟输入流程无关的程序代码就略掉.

//ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {

        synchronized (this) {    

            // do something

            mInputChannel = new InputChannel();

            // do something

            res = mWindowSession.addToDisplay(mWindow, mSeq,                            

                            mWindowAttributes,

                            getHostVisibility(), mDisplay.getDisplayId(),

                            mAttachInfo.mContentInsets, mInputChannel);

            //do something

        }

}

由此可知, new出来的 InputChannel 对象会传入 mWindowSession 的 addToDisplay 函数中, 去查了一下 mWindowSession 是由 IWindowSession 宣告, 一般 Ixxxx 的数据型态都是一个 Binder的接口, 通常功能实作都是会定义在由 Ixxxx 衍生的类别, 搜寻了一下程序代码, Session 继承 IWindowSession , 因此 addToDisplay 函数必在 Session 类别实作.


 

// Session.java

@Override

    public int addToDisplay(IWindow window, int seq,

                        WindowManager.LayoutParams attrs,

                       int viewVisibility, int displayId, Rect outContentInsets,

                       InputChannel outInputChannel) {

                 return mService.addWindow(this, window, seq, attrs,

                                       viewVisibility, displayId,

                                   outContentInsets, outInputChannel);

    }

 


InputChannel对象 继续传入 WindowManagerService (mService 的数据型态是 WindowManagerService ) 的 addWindow 函数.

// WindowManagerService.java

public int addWindow(Session session, IWindow client, int seq,

            WindowManager.LayoutParams attrs, int viewVisibility,

            int displayId,

            Rect outContentInsets, InputChannel outInputChannel) {

           //do something

           String name = win.makeInputChannelName();

           InputChannel[] inputChannels =

                InputChannel.openInputChannelPair(name);

           win.setInputChannel(inputChannels[0]);

           inputChannels[1].transferTo(outInputChannel);

           mInputManager.registerInputChannel(win.mInputChannel,

                                    win.mInputWindowHandle);

           //do something

}


之后就是利用 InputManagerService 的 registerInputChannel 函数将 WindowManagerService 和 ViewRootImpl 之间的 InputChannel 建立起来. 一旦之间的通道建立起来, WindowManagerService 和 ViewRootImpl 之间就可以做输入event的流程沟通. WindowManagerService -> ViewRootImpl,这个方向是 WindowManagerService 通知 ViewRootImpl 去共享内存去取input event. ViewRootImpl -> WindowManagerService,这个方向是 ViewRootImpl 通知 WindowManagerService 已经处理完共享内存的 input event了, 请 WindowManagerService 在检查是否有新的 input event, 若有的话就放入共享内存. 以下就来介绍 input event 流程.

 

        2.2 输入事件处理流程:

                一开机的时候, SystemServer 会启动 InputManagerService, 这时 InputManagerService 又会去启动两个Thread, InputReaderThreadInputDispatcherThread和一个 EventHubInterface . 因此输入事件处理流程跟此三位角色有关系. InputReaderThread从 EventHubInterface抓取新的inputevent, 然后在依各个的eventtype 进入各个的 eventmapper,  各个的 event mapper 处理输入事件完之后, InputReaderThread  将new input 放进 Queue 中. 之后 InputDispatcherThread再从Queue中取出Input Event 放入共享内存中. 此时再通知 View 去共享内存抓取 new Input Event, 取完之后再通知 InputDispatcherThread是否可以再放新的InputEvent到共享内存中, 流程如下

首先先由InputReaderThread 启动开始, 在android启动 thread 是以下的形式.

// InputManager.cpp

mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);

这时候InputReaderThread 的 threadLoop 函数就会被触发.

// InputReader.cpp

bool InputReaderThread::threadLoop() {

    mReader->loopOnce();

    return true;

}

 

void InputReader::loopOnce() {

    //do something

    // 从 /dev/input下获得新的Input event

    mEventHub->getEvents(timeoutMillis, mEventBuffer,

                        EVENT_BUFFER_SIZE);

    //依各个的event type 进入各个的 event mapper

    processEventsLocked(mEventBuffer, count);

 

    //通知 InputDispatcherThread 去处理new input.

    mQueuedListener->flush();

    //do something

}


在loopOnce 函式中作了三件事

1. getEvents,

2. processEventsLocked,

3. flush.

在这篇关心的是输入事件处理流程, 所以就先来看从 EventHub 得到的 input event, InputReader 是如何借着 processEventsLocked 去做处理.

//InputReader.cpp

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {

      //do something

      int32_t deviceId = rawEvent->deviceId;

      //do something

      processEventsForDeviceLocked(deviceId, rawEvent, batchSize);

      //do something

}

 

void InputReader::processEventsForDeviceLocked(int32_t deviceId,

        const RawEvent* rawEvents, size_t count) {

        //do something

        InputDevice* device = mDevices.valueAt(deviceIndex);

        if (device->isIgnored()) {

           //ALOGD("Discarding event for ignored deviceId %d.", deviceId);

           return;

        }

 

        device->process(rawEvents, count);

}

 

void InputDevice::process(const RawEvent* rawEvents, size_t count) {

      //do something

      for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {

         //do something

          for (size_t i = 0; i < numMappers; i++) {

                InputMapper* mapper = mMappers[i];

                mapper->process(rawEvent);

            }

         //do something

      }

      //do something

}

由此可知,InputReader 会利用一个mapper来管理所收到的 input event, 这些mapper 有

1. SwitchInputMapper,

2. VibratorInputMapper,

3. KeyboardInputMapper,

4. CursorInputMapper,

5. TouchInputMapper,

6. SingleTouchInputMapper,

7. MultiTouchInputMapper,

8.JoystickInputMapper等等.

由于这些mapper处理的架构都差不多, 就拿 TouchInputMapper 来作分析


//InputReader.cpp

void TouchInputMapper::process(const RawEvent* rawEvent) {

    // 处理以下的输入事件, 并将各个的Touch value作相对应处理

    mCursorButtonAccumulator.process(rawEvent);

    mCursorScrollAccumulator.process(rawEvent);

    mTouchButtonAccumulator.process(rawEvent);

    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {

        sync(rawEvent->when);

    }

}

 

void TouchInputMapper::sync(nsecs_t when) {

     //do something

     dispatchTouches(when, policyFlags);

     //do something

}

 

void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {

     //do something

     // No pointer id changes so this is a move event.

     // The listener takes care of batching moves so we don't have to deal with

     // that here.

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

    

     //do something

}

 

void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags,

        uint32_t source,

        int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,

        int32_t edgeFlags,

        const PointerProperties* properties, const PointerCoords* coords,

        const uint32_t* idToIndex, BitSet32 idBits,

        int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {

 

        //do something

       

      NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,

            action, flags, metaState, buttonState, edgeFlags,

            mViewport.displayId, pointerCount, pointerProperties,

            pointerCoords,

            xPrecision, yPrecision, downTime);

    getListener()->notifyMotion(&args);

}

 

InputListenerInterface* InputReader::ContextImpl::getListener() {

    return mReader->mQueuedListener.get();

}

最后会发现会将所收到的Touchmotion 信息打包成message,然后利用 QueuedInputListener 将 message 推入 mArgsQueue 向量里.

// InputListener.h

Vector<NotifyArgs*> mArgsQueue;

 

// InputListener.cpp

void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {

    mArgsQueue.push(new NotifyMotionArgs(*args));

}

InputReader处理完有关 TouchMotion input event之后, 便会把新的 Touch Motion input event 放进InboundQueue 流程如下:

//InputReader.cpp

mQueuedListener->flush();

 

//InputListener.cpp

void QueuedInputListener::flush() {

    size_t count = mArgsQueue.size();

    for (size_t i = 0; i < count; i++) {

        NotifyArgs* args = mArgsQueue[i];

        args->notify(mInnerListener);

        delete args;

    }

    mArgsQueue.clear();

}

在此会发现会用个loop来呼叫mArgsQueue vector中的 notify 函数, 继续看下去

//InputListener.cpp

void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {

    listener->notifyMotion(this);

}

在此发现notifyMotion 函数是由 InputListenerInterface 类别的对象所带出来的, 由字符串来看此类别只是当作是一个界面, 所以实作必定是其类别衍生的类别. 搜寻了一下整个程序代码, 发现 InputDispatcherInterface 继承InputListenerInterface,

而 InputDispatcher 继承 InputDispatcherInterface类别, 所以 notifyMotion 函数必定实作在这类别中

// InputDispatcher.cpp

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {

     //do something

    // Policy:

    // - Ignore untrusted events and pass them along.

    // - No special filtering for injected events required at this time.

    // - Filter normal events based on screen state.

    // - For normal events brighten (but do not wake) the screen if currently dim.

     mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/

                                        policyFlags);

     bool needWake;

    { // acquire lock

        mLock.lock();

 

        if (shouldSendMotionToInputFilterLocked(args)) {

            mLock.unlock();

 

            //initialize motion event for secondary display

 

            mLock.lock();

        }

 

        // Just enqueue a new motion event.

        MotionEntry* newEntry = new MotionEntry(args->eventTime,

                args->deviceId, args->source, policyFlags,

                args->action, args->flags, args->metaState, args->buttonState,

                args->edgeFlags, args->xPrecision, args->yPrecision,

                args->downTime,

                args->displayId,

                args->pointerCount, args->pointerProperties,

                args->pointerCoords);

 

        needWake = enqueueInboundEventLocked(newEntry);

        mLock.unlock();

    } // release lock

   

    if (needWake) {

        mLooper->wake();

    }

}

 

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {

    // 将新的 input event 放进 InboundQueue

    bool needWake = mInboundQueue.isEmpty();

    mInboundQueue.enqueueAtTail(entry);

    // do something

    return needWake;

}

 

到此为止,InputReader Thread 已经把新的Touch motion event放进InboundQueue了. 接下来就来看InputDispatcher Thread 的输入事件流程.

同样的从 InputDispatcherThread的启动流程开始分析

// InputDispatcher.cpp

bool InputDispatcherThread::threadLoop() {

    mDispatcher->dispatchOnce();

    return true;

}

 

 

 

void InputDispatcher::dispatchOnce() {

     nsecs_t nextWakeupTime = LONG_LONG_MAX;

    { // acquire lock

        AutoMutex _l(mLock);

        mDispatcherIsAliveCondition.broadcast();

 

        // Run a dispatch loop if there are no pending commands.

        // The dispatch loop might enqueue commands to run afterwards.

        if (!haveCommandsLocked()) {

            dispatchOnceInnerLocked(&nextWakeupTime);

        }

 

        // Run all pending commands if there are any.

        // If any commands were run then force the next poll to wake up

        //immediately.

        if (runCommandsLockedInterruptible()) {

            nextWakeupTime = LONG_LONG_MIN;

        }

    } // release lock

 

    // Wait for callback or timeout or wake.  (make sure we round up, not down)

    nsecs_t currentTime = now();

    int timeoutMillis = toMillisecondTimeoutDelay(currentTime,

                                      nextWakeupTime);

    mLooper->pollOnce(timeoutMillis);  // 用来管理message queue, 负责接收        

                                   // 或发送 message.

}

 

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {

     //do something

    // Ready to start a new event.

    // If we don't already have a pending event, go grab one.

    if (! mPendingEvent) {

        if (mInboundQueue.isEmpty()) {

           //do something

        } else {

           // Inbound queue has at least one entry.

            mPendingEvent = mInboundQueue.dequeueAtHead();

        }

        //do something

        // Get ready to dispatch the event.

        resetANRTimeoutsLocked();   //因为已经取到input event, 所以 reset

                                  //ANR timer.

    }

   

    //do something

    switch (mPendingEvent->type) {

    case EventEntry::TYPE_CONFIGURATION_CHANGED:

       //do something

       break;

    case EventEntry::TYPE_DEVICE_RESET:

       //do something

       break;

    case EventEntry::TYPE_KEY:

       //do something

       break;

    case EventEntry::TYPE_MOTION:

       MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);

       //do something

       done = dispatchMotionLocked(currentTime, typedEntry,

                &dropReason, nextWakeupTime);

       break;

    default:

       break;

    }

 

    if (done) {

        if (dropReason != DROP_REASON_NOT_DROPPED) {

            dropInboundEventLocked(mPendingEvent, dropReason);

        }

 

        releasePendingEventLocked();

        *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up

                                             // immediately

    }

 

}

 

bool InputDispatcher::dispatchMotionLocked(

        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason,

        nsecs_t* nextWakeupTime) {

       

        1. // Preprocessing.

        2. // Clean up if dropping the event.

        3. // support sending secondary display events to input monitors

 

        // Dispatch the motion.

        // do soemthing

       dispatchEventLocked(currentTime, entry, inputTargets);

}

 

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,

        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {

     //do something

     for (size_t i = 0; i < inputTargets.size(); i++) {

        const InputTarget& inputTarget = inputTargets.itemAt(i);

        ssize_t connectionIndex =

                    getConnectionIndexLocked(inputTarget.inputChannel);

        if (connectionIndex >= 0) {

            sp<Connection> connection =

                     mConnectionsByFd.valueAt(connectionIndex);

            prepareDispatchCycleLocked(currentTime, connection, eventEntry,

                                    &inputTarget);

        } else {

            //do something

        }

    }

}

 

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,

        const sp<Connection>& connection, EventEntry* eventEntry, const

        InputTarget* inputTarget) {

       1. // Skip this event if the connection status is not normal.

         // We don't want to enqueue additional outbound events if the

         // connection is broken.

 

      // Split a motion event if needed.

      if (inputTarget->flags & InputTarget::FLAG_SPLIT) {

        ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);

 

         //do something

         enqueueDispatchEntriesLocked(currentTime, connection,

                    splitMotionEntry, inputTarget);

         //do something

         return;

        }

    }

 

    // 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) {

    bool wasEmpty = connection->outboundQueue.isEmpty();

 

    // Enqueue dispatch entries for the requested modes.

    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

            InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);

    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

            InputTarget::FLAG_DISPATCH_AS_OUTSIDE);

    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

            InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);

    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

            InputTarget::FLAG_DISPATCH_AS_IS);

    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);

    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);

 

    // 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) {

 

        //do something

       

        // This is a new event.

        // Enqueue a new dispatch entry onto the outbound queue for this

        // connection.

        DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry,

            inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,

            inputTarget->scaleFactor);

 

         // Apply target flags and update the connection's input state.

 

        // Remember that we are waiting for this dispatch to complete.

 

        // Enqueue the dispatch entry.

        connection->outboundQueue.enqueueAtTail(dispatchEntry);

}

 

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,

        const sp<Connection>& connection) {

 

       // do something

 

       // 检查outboundQueue 中是否有新的 input event.

       while (connection->status == Connection::STATUS_NORMAL

            && !connection->outboundQueue.isEmpty()) {

            // 从 outboundQueue 中取出新的 input event.

            DispatchEntry* dispatchEntry = connection->outboundQueue.head;

            // Publish the event.

            EventEntry* eventEntry = dispatchEntry->eventEntry;

 

            switch (eventEntry->type) {

            case EventEntry::TYPE_KEY:

                //do something

               break;

            case EventEntry::TYPE_MOTION:

                //do something

                // Publish the motion event.

                status =              

                connection->inputPublisher.publishMotionEvent(

                   // some argument.

                );

                break;

            default:

               return;

            }

       }

 

}

 

//InputTransport.cpp

status_t InputPublisher::publishMotionEvent(

        uint32_t seq,

        int32_t deviceId,

        int32_t source,

        int32_t action,

        int32_t flags,

        int32_t edgeFlags,

        int32_t metaState,

        int32_t buttonState,

        float xOffset,

        float yOffset,

        float xPrecision,

        float yPrecision,

        nsecs_t downTime,

        nsecs_t eventTime,

        size_t pointerCount,

        const PointerProperties* pointerProperties,

        const PointerCoords* pointerCoords) {

      InputMessage msg;

    msg.header.type = InputMessage::TYPE_MOTION;

    msg.body.motion.seq = seq;

    msg.body.motion.deviceId = deviceId;

    msg.body.motion.source = source;

    msg.body.motion.action = action;

    msg.body.motion.flags = flags;

    msg.body.motion.edgeFlags = edgeFlags;

    msg.body.motion.metaState = metaState;

    msg.body.motion.buttonState = buttonState;

    msg.body.motion.xOffset = xOffset;

    msg.body.motion.yOffset = yOffset;

    msg.body.motion.xPrecision = xPrecision;

    msg.body.motion.yPrecision = yPrecision;

    msg.body.motion.downTime = downTime;

    msg.body.motion.eventTime = eventTime;

    msg.body.motion.pointerCount = pointerCount;

    for (size_t i = 0; i < pointerCount; i++) {

        msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);

        msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);

    }

    return mChannel->sendMessage(&msg);

}

 

status_t InputChannel::sendMessage(const InputMessage* msg) {

    size_t msgLength = msg->size();

    ssize_t nWrite;

    do {

        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT |

               MSG_NOSIGNAL);

    } while (nWrite == -1 && errno == EINTR);

 

    if (nWrite < 0) {

        int error = errno;

        if (error == EAGAIN || error == EWOULDBLOCK) {

            return WOULD_BLOCK;

        }

        if (error == EPIPE || error == ENOTCONN) {

            return DEAD_OBJECT;

        }

        return -error;

    }

 

    if (size_t(nWrite) != msgLength) {

        return DEAD_OBJECT;

    }

    return OK;

}

上面呼叫了哪么多层函数, InputDispatcherThread 就只做了以下几件事:

1. 从InboundQueue取 newinput event 处理, 处理完放进OutboundQueue

2. 从OutboundQueue 取 new input event 处理, 处理完放进 inputMessage.

3. 利用::send 函数送 inputMessage.

世上万物常是一体两面, 在程序设计上也是如此, 因此有了sendMessage函数设计, 必有一个receiveMessage的函数. 所以有了 InputChannel::sendMessage 就会提供 InputChannel::receiveMessage 函数作接收message的处理. 搜寻了一下程序代码发现呼叫 InputChannel::receiveMessage 函数的地方是在InputConsumer::consume函数中. 而这consume函数又是在哪被呼叫呢? 此流程牵扯到Thread 通讯课题, 在这不做详细分析, 为了篇幅只能做简单的说明, 在android中每一个Process都有一个looper,此looper里有一个messageQueue,messageQueue中有很多来自此process中不同的thread所发出来的message.管理这些message 就是这个名为 looper 的对象. 因此就去搜寻一下跟looper 相关的程序代码, 发现android 有定义一个 LooperCallback 的抽象类, 此抽象类里有一个purevirtual function handleEvent 函数, 因此只要找到谁继承LooperCallback类别, 就能找到handleEvent 函数实作的地方. 最后在 NativeInputEventReceiver 发现handleEvent 函数实作足迹.

 

// android_view_InputEventReceiver.cpp

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {

    //do something

    status_t status = consumeEvents(env, false /*consumeBatches*/, -1);

    // do something

}

 

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,

        bool consumeBatches, nsecs_t frameTime) {

    //do something

    bool skipCallbacks = false;  // 用来做为通知是否已完成dispach input event

                            // 的一个判断值.

    for (;;) {

        uint32_t seq;

        InputEvent* inputEvent;

        //果然在这里发现了呼叫 InputConsumer::consume 函数的地方

        status_t status = mInputConsumer.consume(&mInputEventFactory,

                consumeBatches, frameTime, &seq, &inputEvent);

 

        //do something

        if (!skipCallbacks) {

            jobject inputEventObj;

            switch (inputEvent->getType()) {

            case AINPUT_EVENT_TYPE_KEY:

                inputEventObj = android_view_KeyEvent_fromNative(env,

                        static_cast<KeyEvent*>(inputEvent));

                break;

 

            case AINPUT_EVENT_TYPE_MOTION:

                inputEventObj =

                      android_view_MotionEvent_obtainAsCopy(env,

                             static_cast<MotionEvent*>(inputEvent));

                break;

 

            default:

                assert(false); // InputConsumer should prevent this from ever

                           // happening

                inputEventObj = NULL;

            }

 

            if (inputEventObj) {

                env->CallVoidMethod(mReceiverObjGlobal,

                     gInputEventReceiverClassInfo.dispatchInputEvent,

                     seq, inputEventObj);

                if (env->ExceptionCheck()) {

                    skipCallbacks = true;

                }

            } else {

                skipCallbacks = true;

            }

        }

 

        if (skipCallbacks) {

            mInputConsumer.sendFinishedSignal(seq, false);

        }

 

    }

}

由这段程序代码可以发现, 当利用InputConsumer对象收到由 InputDispatcherThread 送过来的InputEvent message时, 便会利用一个boolean variable skipCallbacks 当作一个是否完成dispatch input event的判断值. 一收到inputevent马上分析为是 Key event type 还是 Motionevent type. 由于我们这里是以 Motion event type 为例, 所以就分析 Motionevent type 这个 case流程.

 

// android_view_InputEventReceiver.cpp

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,

        bool consumeBatches, nsecs_t frameTime) {

     //do something

     case AINPUT_EVENT_TYPE_MOTION:

                inputEventObj =

                      android_view_MotionEvent_obtainAsCopy(env,

                             static_cast<MotionEvent*>(inputEvent));

                break;

     //do something

}

 

// android_view_MotionEvent.cpp

jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const

      MotionEvent* event) {

          // 回呼MotionEvent  Java Layer 配置一块 MotionEvent type 

          // 物件.

          jobject eventObj =  

            env->CallStaticObjectMethod(gMotionEventClassInfo.clazz,

                                gMotionEventClassInfo.obtain);

          // eventObj exception handler

          // MotionEvent java layer 读取MotionEvent 对象指针值.

          MotionEvent* destEvent =  

                  android_view_MotionEvent_getNativePtr(env, eventObj);

          if (!destEvent) {

               destEvent = new MotionEvent();

               android_view_MotionEvent_setNativePtr(env, eventObj,

                                                 destEvent);

           }

 

         destEvent->copyFrom(event, true);

         return eventObj;

}

到此利用java layer来配置一块MotionEvent 对象来使用. 为何要这么大费周章还要去回呼Javalayer作配置对象的动作, 推论应该是要藉由DVM的 GC来做回收未用到的内存. 接下来继续分析后续动作

// android_view_InputEventReceiver.cpp

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,

        bool consumeBatches, nsecs_t frameTime) {

        //do something

        //do something

        // 将上面所得到的MotionEvent 对象指针值在传入 Java Layer  

        // 函数里

        env->CallVoidMethod(mReceiverObjGlobal,

                      gInputEventReceiverClassInfo.dispatchInputEvent,

                        seq, inputEventObj);

        //do something

}

 

//InputEventReceiver.java

// Called from native code.

@SuppressWarnings("unused")

private void dispatchInputEvent(int seq, InputEvent event) {

        mSeqMap.put(event.getSequenceNumber(), seq);

        onInputEvent(event);

}

 

 

/**

     * Called when an input event is received.

     * The recipient should process the input event and then call {@link

       #finishInputEvent}

     * to indicate whether the event was handled.  No new input events will be

       received

     * until {@link #finishInputEvent} is called.

     *

     * @param event The input event that was received.

*/

public void onInputEvent(InputEvent event) {

        finishInputEvent(event, false);

}

 

到这里先停一下, 若继续分析下去, 会发现似乎直接就呼叫 finishInputEvent 函数, 然后就送finishmessage 通知 InputDispatcherThread 之后, 就完成了这一个输入事件流程了. 然而, 依照过去写app的经验, 一般在app若要接收一些Touchevent 会有个 call back function onTouch 函数要实作, 方便app可以接收到Touchevent 然后作相关的应用. 然而刚刚分析的输入事件的流程似乎没有去呼叫 onTouch函数, 这到底是怎么一回事? 原因在于 InputEventReceiver 这个类别, 这个类别是属于 abstract 类别, 在java的语法中, abstract类别即使类别中的成员函数都有实作, 也是无法实体化的, 因此只能有abstract类别的衍生类别才能实体化. 搜寻了一下程序代码发现了几个abstractInputEventReceiver类别的衍生类别, 跟InputEvent处理有关的衍生类别就是WindowInputEventReceiver , 原因如下, 再一开始ViewRootImpl在作 setView 时, 除了new 一个新的 InputChannel 对象之后, 又 new 了一个 WindowInputEventReceiver 对象. 此 WindowInputEventReceiver 类别正好又overwrite onInputEvent 函数, 因此可以大胆推测dispatchInputEvent呼叫的 onInputEvent 函数, 会是此类别的 onInputEvent 函数, 就在从 WindowInputEventReceiver 中的 onInputEvent 函数开始分析.

// ViewRootImpl.java

// 此类别是定义在ViewRootImpl 类别中最前面又是挂 final, java的语法// 中代表此类别只能给ViewRootImpl类别中使用且无法被继承.

final class WindowInputEventReceiver extends InputEventReceiver {

      //data member

      @Override

        public void onInputEvent(InputEvent event) {

            enqueueInputEvent(event, this, 0, true);

        }

      // member function

}

 

 

void enqueueInputEvent(InputEvent event,

            InputEventReceiver receiver, int flags, boolean processImmediately) {

        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);

 

        // Always enqueue the input event in order, regardless of its time stamp.

        // We do this because the application or the IME may inject key events

        // in response to touch events and we want to ensure that the injected

        // keys are processed in the order they were received and we cannot

        // trust that the time stamp of injected events are monotonic.

        QueuedInputEvent last = mFirstPendingInputEvent;

        if (last == null) {

            mFirstPendingInputEvent = q;

        } else {

            while (last.mNext != null) {

                last = last.mNext;

            }

            last.mNext = q;

        }

 

        if (processImmediately) {

            doProcessInputEvents();    //一般的input event都是即使的

        } else {

            scheduleProcessInputEvents();

        }

    }

 

void doProcessInputEvents() {

        while (mCurrentInputEvent == null && mFirstPendingInputEvent != null)   

        {

            QueuedInputEvent q = mFirstPendingInputEvent;

            mFirstPendingInputEvent = q.mNext;

            q.mNext = null;

            mCurrentInputEvent = q;

            deliverInputEvent(q);

        }

 

        // We are done processing all input events that we can process right now

        // so we can clear the pending flag immediately.

       

    }

 

private void deliverInputEvent(QueuedInputEvent q) {

     // do something

     if (q.mEvent instanceof KeyEvent) {

                deliverKeyEvent(q);

     } else {

             final int source = q.mEvent.getSource();

             if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0)

            {

                    deliverPointerEvent(q);

            } else if ((source &

                    InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {

                    deliverTrackballEvent(q);

            } else {

                    deliverGenericMotionEvent(q);

            }

     }

 

    // do something

}

 

private void deliverPointerEvent(QueuedInputEvent q) {

     // If there is no view, then the event will not be handled.

     if (mView == null || !mAdded) {

            finishInputEvent(q, false);

            return;

     }

     // Translate the pointer event for compatibility, if needed.

 

     // Enter touch mode on down or scroll.

    

     // Offset the scroll position.

 

     // Remember the touch position for possible drag-initiation.

 

     // Dispatch touch to view hierarchy.

        boolean handled = mView.dispatchPointerEvent(event);

 

     if (handled) {

            finishInputEvent(q, true);

            return;

     }

 

     // Pointer event was unhandled.

     finishInputEvent(q, false);

}

 

由此可以发现只要检查到没有view或是无法掌握的inputevent就会被ignore掉不去处理.最后会去呼叫 View 类别的 dispatchTouchEvent 函数.

//View .java

public boolean dispatchTouchEvent(MotionEvent event) {

        if (mInputEventConsistencyVerifier != null) {

            mInputEventConsistencyVerifier.onTouchEvent(event, 0);

        }

 

        if (onFilterTouchEventForSecurity(event)) {

            //noinspection SimplifiableIfStatement

            ListenerInfo li = mListenerInfo;

            if (li != null && li.mOnTouchListener != null && (mViewFlags &

                                  ENABLED_MASK) == ENABLED

                    && li.mOnTouchListener.onTouch(this, event)) {

                return true;

            }

            // 主要是用来实作触控的一般通用的功能, ex press, click, long

            //  press etc.

            if (onTouchEvent(event)) {

                return true;

            }

        }

 

        if (mInputEventConsistencyVerifier != null) {

            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);

        }

        return false;

    }

终于发现呼叫 onTouch 函数的地方了. 在这里只要app有注册onTouchListener 接口, onTouch函数就会被触发了. 到目前为止分析的方向是WindowManagerService-> ViewRootImpl, 接下来 ViewRootImpl 处理完 inputevent 之后, 再来分析 ViewRootImpl -> WindowManagerService这方向. 由前面的 deliverPointerEvent 函数分析中, 会发现都会解由 finishInputEvent来完成这一次的输入事件流程. 就由 finishInputEvent函数开始分析

// ViewRootImpl.java

private void finishInputEvent(QueuedInputEvent q, boolean handled) {

     //do something

     if (q.mReceiver != null) {

            q.mReceiver.finishInputEvent(q.mEvent, handled);

     } else {

            q.mEvent.recycleIfNeededAfterDispatch();

     }

     //do something

}

 

// InputEventReceiver.cpp

public final void finishInputEvent(InputEvent event, boolean handled) {

    //do something

    nativeFinishInputEvent(mReceiverPtr, seq, handled);

    //do something

}

 

// android_view_InputEventReceiver.cpp

static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr,

        jint seq, jboolean handled) {

      sp<NativeInputEventReceiver> receiver =

            reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);

      status_t status = receiver->finishInputEvent(seq, handled);

     // exception handler

}

 

status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {

     // do something

     status_t status = mInputConsumer.sendFinishedSignal(seq, handled);

    // exception handler

}

 

// InputTransport.cpp

status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {

    // do something

    // Send finished signal for the last message in the batch.

    return sendUnchainedFinishedSignal(seq, handled);

}

 

status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {

    InputMessage msg;

    msg.header.type = InputMessage::TYPE_FINISHED;

    msg.body.finished.seq = seq;

    msg.body.finished.handled = handled;

    return mChannel->sendMessage(&msg);

}

 

一旦ViewRootImpl 藉由 InputChannel对象传送 finish的message 时, 这时

InputDispatcher类别的 handleReceiveCallback 函数就会被触发. 原因在于InputDispatcher在初始化的时候有去做register InputChannel 的动作, 在 register InputChannel时, 会在自己new 出来的 looper对象上增加一个 callback function handleReceiveCallback.

// InputDispatcher.cpp

mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);

 

int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {

    // do something

    for (;;) {

      // do something

       status = connection->inputPublisher.receiveFinishedSignal(&seq,

                                                  &handled);

       // do something

 

       d->finishDispatchCycleLocked(currentTime, connection, seq,

                                  handled);

       gotOne = true;

    }

}

 

// InputTransport.cpp

status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {

    //do something

    status_t result = mChannel->receiveMessage(&msg);

 

    //do something

 

    *outSeq = msg.body.finished.seq;

    *outHandled = msg.body.finished.handled;

    return OK;

}

 

// InputDispatcher.cpp

void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,

        const sp<Connection>& connection, uint32_t seq, bool handled) {

     //do something

     // Notify other system components and prepare to start the next dispatch cycle.

    onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);

}

 

void InputDispatcher::onDispatchCycleFinishedLocked(

        nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq,

        bool handled) {

    CommandEntry* commandEntry = postCommandLocked(

    & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);

    commandEntry->connection = connection;

    commandEntry->eventTime = currentTime;

    commandEntry->seq = seq;

    commandEntry->handled = handled;

}

 

void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(

        CommandEntry* commandEntry) {

     //do something

     // Start the next dispatch cycle for this connection.

        startDispatchCycleLocked(now(), connection);

}

 

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,

        const sp<Connection>& connection) {

 

    //检查outboundQueue 中是否还有新的input event.

    while (connection->status == Connection::STATUS_NORMAL

            && !connection->outboundQueue.isEmpty()) {

        DispatchEntry* dispatchEntry = connection->outboundQueue.head;

        dispatchEntry->deliveryTime = currentTime;

 

        // Publish the event.

        status_t status;

        EventEntry* eventEntry = dispatchEntry->eventEntry;

        switch (eventEntry->type) {

        case EventEntry::TYPE_KEY: {

            KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);

            // Publish the key event.

            status =

            connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,

                    keyEntry->deviceId, keyEntry->source,

                    dispatchEntry->resolvedAction,

                    dispatchEntry->resolvedFlags,

                    keyEntry->keyCode, keyEntry->scanCode,

                    keyEntry->metaState, keyEntry->repeatCount,

                    keyEntry->downTime,

                    keyEntry->eventTime);

            break;

        }

 

        case EventEntry::TYPE_MOTION: {

            MotionEntry* motionEntry =

                        static_cast<MotionEntry*>(eventEntry);

 

            PointerCoords scaledCoords[MAX_POINTERS];

            const PointerCoords* usingCoords = motionEntry->pointerCoords;

 

            // Set the X and Y offset depending on the input source.

            float xOffset, yOffset, scaleFactor;

              //do something

            } else {

                xOffset = 0.0f;

                yOffset = 0.0f;

                scaleFactor = 1.0f;

 

                // We don't want the dispatch target to know.

                if (dispatchEntry->targetFlags &

                  InputTarget::FLAG_ZERO_COORDS) {

                    for (size_t i = 0; i < motionEntry->pointerCount; i++) {

                        scaledCoords[i].clear();

                    }

                    usingCoords = scaledCoords;

                }

            }

 

            // Publish the motion event.

            //通知ViewRootImpl 去共享内存抓取新的 input event

            status =

           connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,

                    motionEntry->deviceId, motionEntry->source,

                    dispatchEntry->resolvedAction,

                    dispatchEntry->resolvedFlags,

                    motionEntry->edgeFlags, motionEntry->metaState,

                    motionEntry->buttonState,

                    xOffset, yOffset,

                    motionEntry->xPrecision, motionEntry->yPrecision,

                    motionEntry->downTime, motionEntry->eventTime,

                    motionEntry->pointerCount,

                    motionEntry->pointerProperties,

                    usingCoords);

            break;

        }

 

        default:

            ALOG_ASSERT(false);

            return;

        }

 

        // Check the result.

        if (status) {

           if (status == WOULD_BLOCK) {

                if (connection->waitQueue.isEmpty()) {

                    abortBrokenDispatchCycleLocked(currentTime,

                         connection, true /*notify*/);

                } else {

                    // Pipe is full and we are waiting for the app to finish

                    //process some events

                    // before sending more events to it.

                    connection->inputPublisherBlocked = true;

                }

            } else {

                abortBrokenDispatchCycleLocked(currentTime, connection,

                                           true /*notify*/);

            }

            return;

        }

 

        // Re-enqueue the event on the wait queue.

        connection->outboundQueue.dequeue(dispatchEntry);

        traceOutboundQueueLengthLocked(connection);

        connection->waitQueue.enqueueAtTail(dispatchEntry);

        traceWaitQueueLengthLocked(connection);

    }  //while loop end

}

由此可知在 InputDispatcher 一收到InputConsumer对象送的 finish message之后, 就马上去呼叫startDispatchCycleLocked 函数去检查 outboundQueue 里面还有没有新的inputevent. 若有的话就放入 InputMessage 共享内存, 然后通知 ViewRootImpl 去共享内存抓取新的 inputevent. 若没有新的 input event, 就不做事等待有新的inputevent进 outboundQueue.


展开阅读全文

没有更多推荐了,返回首页