Android系统源码剖析-事件分发

作者: Jensen95 | 来源:发表于2018-01-16 16:09 被阅读26次

    前言

    上一篇文章中,对于事件的监控和获取做了分析,在拿到事件之后,后续是如何处理分发的呢?本篇文章主要针对在通过getEvent获取到事件之后,后续的相关分发处理流程。

    事件处理分发

    InputReaderThread函数不断地调用looperOnce函数,不断的从中读取事件,那么下一个问题来了,读取到事件要放置到哪里,又在哪里被消耗掉了呢?也就是事件接下来的流向问题。让我们回到looperOnce之前。

    事件分发

    processEventsLocked

    在调用了getEvent之后,获得了事件之后,接着调用了相应的处理函数processEventsLocked

    void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
        for (const RawEvent* rawEvent = rawEvents; count;) {
            int32_t type = rawEvent->type;
            size_t batchSize = 1;
            if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
                int32_t deviceId = rawEvent->deviceId;
                while (batchSize < count) {
                    if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                            || rawEvent[batchSize].deviceId != deviceId) {
                        break;
                    }
                    batchSize += 1;
                }
                processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
            } else {
                switch (rawEvent->type) {
                case EventHubInterface::DEVICE_ADDED:
                    addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                case EventHubInterface::DEVICE_REMOVED:
                    removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                case EventHubInterface::FINISHED_DEVICE_SCAN:
                    handleConfigurationChangedLocked(rawEvent->when);
                    break;
                default:
                    ALOG_ASSERT(false); // can't happen
                    break;
                }
            }
            count -= batchSize;
            rawEvent += batchSize;
        }
    }
    

    首先对于事件类型进行了判断,如果事件不是合成事件,则会对其DeviceID进行判断,通过对其判断来确定batchSize等,如果是合成事件,则会具体判断,判断是设备的添加,设备的移除,完成设备扫描等等,然后对事件分别进行处理,这里我们只关心对于设备自身产生的事件。也就是触摸屏相关的事件。也就是processEventsForDeviceLocked函数中所进行的操作。

    事件派发到InputDevice
    void InputReader::processEventsForDeviceLocked(int32_t deviceId,
            const RawEvent* rawEvents, size_t count) {
        ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
        if (deviceIndex < 0) {
            return;
        }
    
        InputDevice* device = mDevices.valueAt(deviceIndex);
        if (device->isIgnored()) {
            return;
        }
    
        device->process(rawEvents, count);
    }
    

    根据事件获得相应的设备类型,然后将事件交给相应的设备处理。判断是否忽略该事件,如果不是忽略该事件,则会调用相应设备的process方法进行处理。

    事件派发到InputMapper

    InputDevice的process方法

    void InputDevice::process(const RawEvent* rawEvents, size_t count) {
         ....
        for (size_t i = 0; i < numMappers; i++) {
               InputMapper* mapper = mMappers[i];
               mapper->process(rawEvent);
        }
        ....
    }
    

    这里的事件又交给了InputMapper来处理

    InputMapper

    InputMapper对应了很多的子类,这里根据事件的类型进行相应的派发,处理。事件到了这里之后,这里来看一下对于触摸屏事件的处理的相关类和处理函数。

    void TouchInputMapper::process(const RawEvent* rawEvent) {
        mCursorButtonAccumulator.process(rawEvent);
        mCursorScrollAccumulator.process(rawEvent);
        mTouchButtonAccumulator.process(rawEvent);
    
        if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
            sync(rawEvent->when);
        }
    }
    

    通过这里的函数处理,我们继续追踪函数的数据流向。对于相关事件会调用TouchInputMapper的sync方法来进行处理。

    void TouchInputMapper::sync(nsecs_t when) {
        .....
        processRawTouches(false /*timeout*/);
    }
    
    
    void TouchInputMapper::processRawTouches(bool timeout) {
            ....
            cookAndDispatch(mCurrentRawState.when);
            ....
    }
    

    在相关的函数调用之后,最终调用了dispatchTouches

    void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
          ....
        dispatchMotion();
          ....
    }
    

    对于dispatchTouches中,会根据记录的上一次的触摸位置,对事件的类型进行判断,然后做相应的分发,事件类型有抬起,下落,移动等,然后对相应的事件进行分发。无论是对于何种类型的事件派发,最终被调用到的都是dispatchMotion()方法。

    对于相关事件的分发最终调用到了dispatchMotion(),对事件数据进行组装之后,调用了

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

    这里对于事件进行了封装,构造出一个NotifyMotionArgs,在整个传递流程做的比较多的就是通过对于事件进行一系列的判断,然后进行一系列的封装。接下来的执行是调用QueuedInputListener的notifyMotion,将构造的事件添加到其中的一个Args队列之中。

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

    notifyMotion函数实现

    void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
        mArgsQueue.push(new NotifyMotionArgs(*args));
    }
    

    之后又调用了QueuedInputListenerflush方法。遍历事件的队列,然后对其逐一调用notify函数。

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

    NotifyArgs的notify函数实现

    void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
        listener->notifyMotion(this);
    }
    

    对于这个listener的创建来自于InputReader构建的时候。

    mQueuedListener = new QueuedInputListener(listener);
    
     mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    

    而这里的Listener则是InputDispatcher,InputDispatcher 的notifyMotion实现源码。

    void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
        .....
       MotionEvent event;
       event.initialize(args->deviceId, args->source, args->action, args->actionButton,
                        args->flags, args->edgeFlags, args->metaState, args->buttonState,
                        0, 0, args->xPrecision, args->yPrecision,
                        args->downTime, args->eventTime,
                        args->pointerCount, args->pointerProperties, args->pointerCoords);
        ....
      MotionEntry* newEntry = new MotionEntry(args->eventTime,
                    args->deviceId, args->source, policyFlags,
                    args->action, args->actionButton, args->flags,
                    args->metaState, args->buttonState,
                    args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
                    args->displayId,
                    args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
       needWake = enqueueInboundEventLocked(newEntry);
        ....
       if (needWake) {
          mLooper->wake();
       }
    }
    

    在该函数中,所做的事情是对于所传递的参数,构造MotionEntry,然后将其加入到enqueueInboundEventLocked之中。然后唤醒其中的looper。

    bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
        bool needWake = mInboundQueue.isEmpty();
        mInboundQueue.enqueueAtTail(entry);
        ...
        //进行一些事件和窗口相关的判断处理
    }
    

    Dispatcher开启的线程中,每次循环的操作如何?

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

    Dispatcher下dispatchOnce的实现

    void InputDispatcher::dispatchOnce() {
        ...
       dispatchOnceInnerLocked(&nextWakeupTime);
        ...
    }
    
    void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
       ....
       mPendingEvent = mInboundQueue.dequeueAtHead();
       ....
    
       switch (mPendingEvent->type) {
            case EventEntry::TYPE_MOTION: {
            MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
            if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
                dropReason = DROP_REASON_APP_SWITCH;
            }
            if (dropReason == DROP_REASON_NOT_DROPPED
                    && isStaleEventLocked(currentTime, typedEntry)) {
                dropReason = DROP_REASON_STALE;
            }
            if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
                dropReason = DROP_REASON_BLOCKED;
            }
            done = dispatchMotionLocked(currentTime, typedEntry,
                    &dropReason, nextWakeupTime);
            break;
        }
        ....
       }
    }
    

    从mInboudQueue中,获取到事件,然后对事件类型进行判断,判断之后调用了dispatchMotionLocked函数,来继续进行事件的传递。

    bool InputDispatcher::dispatchMotionLocked(
            nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
          ....
          Vector<InputTarget> inputTargets;
    if (isPointerEvent) {
            // Pointer event.  (eg. touchscreen)
          //寻找目标窗口
            injectionResult = findTouchedWindowTargetsLocked(currentTime,
                    entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
        } else {
            // Non touch event.  (eg. trackball)
            injectionResult = findFocusedWindowTargetsLocked(currentTime,
                    entry, inputTargets, nextWakeupTime);
        }
        ....
        dispatchEventLocked(currentTime, entry, inputTargets);
        return true;
    }
    
    • dispatchEventLocked
    void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
        ....
        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) {
                sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
                prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
            } 
        }
    }
    

    获得目标输入,根据InputChannel获取相应的连接,然后调用prepareDispatchCycleLocked(),进行事件的派发。
    enqueueDispatchEntriesLocked,在该方法中又调用了startDispatchCycleLocked方法。其实现为

    void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
            const sp<Connection>& connection) {
       EventEntry* eventEntry = dispatchEntry->eventEntry;
        ....
       switch (eventEntry->type) {
          ....
        case EventEntry::TYPE_MOTION: {
          status = connection->inputPublisher.publishMotionEvent( ....);    
          break;
        }
        ....
       }
        ...
    }
    

    至此调用了connection 的inputPublisher的publishMotionEvent方法将事件分发消耗。

    InputPublisher定义在InputTransport.cpp中

    status_t InputPublisher::publishMotionEvent(...) {
      ....
      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.actionButton = actionButton;
      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 (uint32_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);
    }
    

    该方法所执行的操作是利用传入的触摸信息,构建点击消息,然后通过InputChannel将消息发送出去。这里引出了InputChannel,在此,我们通InputPublisher的创建反推出InputChannel是何时被引入的,何时被创建的。从而进一步分析其作用。在分析之前先让我们来对上述的分析过程做一个总结。

    触摸事件读取分发过程

    ReaderThread开启后会从EventHub中轮询获取时间,获取到事件之后,将进行一系列的处理,对事件进行加工包装,然后传递给相应的InputDevice,InputMapper,然后将包装的事件添加到一个事件队列中,InputDispatcher的线程则会在轮询读取该线程中的事件,然后将其再次进行做判断处理后,传递,最终到达InputChannel,通过InputChannel,来将数据发送出去。

    事件产生读取分发

    到此,对于输入事件,我们已经分析到了InputChannel,对于其上的具体分析转化,将是接下来分析的核心。

    InputChannel

    从上面分析可以看到事件传递部分最后是通过InputChannel所发送出去的,那么InputChannel是在何时被创建的呢?何时被InputManager所使用的呢?同时,对于InputReaderThread和InputDispatcherThread是运行在SystemServer进程中的,而我们的应用进程是和其不在同一个进程中的。这之间一定也是有进程间的通信机制在里面。具体是如何实现的呢?这里我们从InputChannel的创建着手来看。

    InputChannel的创建是在 ViewRootImplsetView方法中。

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        ....
      if ((mWindowAttributes.inputFeatures
                            & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
           mInputChannel = new InputChannel();
       }
      ....
      res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                                getHostVisibility(), mDisplay.getDisplayId(),
                                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                mAttachInfo.mOutsets, mInputChannel);
      ....
    }
    

    这里对于ViewRootImpl和WindowSession相关暂且不介绍,对于这方面的知识,需要很大的篇幅来介绍,这里先只是讲到是在这里创建的,对于其相关的内容将在后续的文章中介绍。这里首先是创建了一个InputChannel,然后将其调用了WindowSessionaddToDisplay方法将其作为参数传递。

    public InputChannel() {
    }
    

    在InputChannel中的方法都为调用了相应的native方法。这里调用的addToDisplay将会把InputChannel添加到WindowManagerService中。会调用WMS的addWindow方法。

     public int addWindow(Session session, IWindow client, int seq,
                WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
                Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
                InputChannel outInputChannel) {
          ....
    
          final boolean openInputChannels = (outInputChannel != null
                        && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
          if  (openInputChannels) {
              win.openInputChannel(outInputChannel);
          }
          ....
    }
    

    对于InputChannel的相关处理调用了WindowState的openInputChannel方法。

    void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
         }
         String name = makeInputChannelName();
         InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
         mInputChannel = inputChannels[0];
         mClientChannel = inputChannels[1];
         mInputWindowHandle.inputChannel = inputChannels[0];
         if (outInputChannel != null) {
           mClientChannel.transferTo(outInputChannel);
           mClientChannel.dispose();
           mClientChannel = null;
          } else {
             mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
          }
           mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
    }
    

    首先调用了InputChannel的openInputChannelPair方法,该方法调用了InputChannel的native方法nativeOpenInputChannelPair,创建了两个InputChannel,对其中一个通过InputManager进行了InputChannel的注册。对于InputChannel的相关Native的实现是在InputTransport中,nativeOpenInputChannelPair的源码如下。

    status_t InputChannel::openInputChannelPair(const String8& name,
            sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
        int sockets[2];
        if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
            status_t result = -errno;
            outServerChannel.clear();
            outClientChannel.clear();
            return result;
        }
    
        int bufferSize = SOCKET_BUFFER_SIZE;
        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    
        String8 serverChannelName = name;
        serverChannelName.append(" (server)");
        outServerChannel = new InputChannel(serverChannelName, sockets[0]);
    
        String8 clientChannelName = name;
        clientChannelName.append(" (client)");
        outClientChannel = new InputChannel(clientChannelName, sockets[1]);
        return OK;
    }
    
    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 || error == ECONNREFUSED || error == ECONNRESET) {
                return DEAD_OBJECT;
            }
            return -error;
        }
    
        if (size_t(nWrite) != msgLength) {
            return DEAD_OBJECT;
        }
        return OK;
    }
    

    接收消息,通过读socket的方式来读取消息。

    status_t InputChannel::receiveMessage(InputMessage* msg) {
        ssize_t nRead;
        do {
            nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
        } while (nRead == -1 && errno == EINTR);
    
        if (nRead < 0) {
            int error = errno;
            if (error == EAGAIN || error == EWOULDBLOCK) {
                return WOULD_BLOCK;
            }
            if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {
                return DEAD_OBJECT;
            }
            return -error;
        }
    
        if (nRead == 0) { // check for EOF
            return DEAD_OBJECT;
        }
    
        if (!msg->isValid(nRead)) {
            return BAD_VALUE;
        }
        return OK;
    }
    

    接收端的消息由谁来触发呢?是如何触发开始接受消息,消息如何在传到InputChannel之后,进行的进一步的数据传递呢?这是接下来所要去分析的,这里先对上面InputChannel进行一个总结。

    InputChannel数据传输

    之前的setView中,我们创建了InputChannel之后,开启了对于InputChannel中输入事件的监听。

    if (mInputChannel != null) {
       if (mInputQueueCallback != null) {
           mInputQueue = new InputQueue();
           mInputQueueCallback.onInputQueueCreated(mInputQueue);
      }
       mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                                Looper.myLooper());
    }
    

    WindowInputEventReceiver的构造函数如下,其继承自InputEventReceiver。

    final class WindowInputEventReceiver extends InputEventReceiver {
         public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
         }
          ....
    }
    

    InputEventReceiver的构造函数源码如下

    public InputEventReceiver(InputChannel inputChannel, Looper looper) {
         ....
         mInputChannel = inputChannel;
         mMessageQueue = looper.getQueue();
         mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                    inputChannel, mMessageQueue);
      }
    

    这里调用了native方法来做初始化,相关的native方法的实现在android_view_InputEventReceiver.cpp

    static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
            jobject inputChannelObj, jobject messageQueueObj) {
       ....
      sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
                inputChannelObj);
      sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
      sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
                receiverWeak, inputChannel, messageQueue);
        status_t status = receiver->initialize();
      .....
    }
    

    根据传入的InputChannelMessageQueue,创建一个NativeInputEventReceiver,然后调用其initialize方法。

    status_t NativeInputEventReceiver::initialize() {
        setFdEvents(ALOOPER_EVENT_INPUT);
        return OK;
    }
    

    initialize()方法中,只调用了一个函数setFdEvents

    void NativeInputEventReceiver::setFdEvents(int events) {
        if (mFdEvents != events) {
            mFdEvents = events;
            int fd = mInputConsumer.getChannel()->getFd();
            if (events) {
                mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
            } else {
                mMessageQueue->getLooper()->removeFd(fd);
            }
        }
    }
    

    从InputConsumer中获取到channel的fd,然后调用Looper的addFd方法。

    int ALooper_addFd(ALooper* looper, int fd, int ident, int events,
            ALooper_callbackFunc callback, void* data) {
        return ALooper_to_Looper(looper)->addFd(fd, ident, events, callback, data);
    }
    

    Looper的addFd的实现如下

    int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
        Request request;
        request.fd = fd;
        request.ident = ident;
        request.events = events;
        request.seq = mNextRequestSeq++;
        request.callback = callback;
         request.data = data;
         if (mNextRequestSeq == -1) mNextRequestSeq = 0;
         struct epoll_event eventItem;
         request.initEventItem(&eventItem);
         ssize_t requestIndex = mRequests.indexOfKey(fd);
          if (requestIndex < 0) {
              int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
              if (epollResult < 0) {
                    return -1;
                }
             mRequests.add(fd, request);
           } 
    }
    

    该方法所执行的操作就是对传递的fd添加epoll监控,Looper会循环调用pollOnce方法,而pollOnce方法的核心实现就是pollInner。其代码大致实现内容为等待消息的到来,当有消息到来后,根据消息类型做一些判断处理,然后调用其相关的callback。我们当前是对于开启的socket的一个监听,当有数据到来,我们便会执行相应的回调。这里对于InputChannel的回调是在调用了NativeInputEventReceiver的handleEvent方法。

    int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
        .....
       if (events & ALOOPER_EVENT_INPUT) {
            JNIEnv* env = AndroidRuntime::getJNIEnv();
            status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
            mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
            return status == OK || status == NO_MEMORY ? 1 : 0;
        }
        ....
        return 1;
    }
    

    对于Event的处理,这里调用consumeEvents来对事件进行处理。

    status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
            bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
        ...
        for(;;) {
          ...
         InputEvent* inputEvent;
         status_t status = mInputConsumer.consume(&mInputEventFactory,
                    consumeBatches, frameTime, &seq, &inputEvent);
            ...
        }
       ...
    }
    

    InputConsumer是在InputTransport中做的声明。

    status_t InputConsumer::consume(InputEventFactoryInterface* factory,
            bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
        while (!*outEvent) {
             ....
             status_t result = mChannel->receiveMessage(&mMsg);
              ....
        }
    }
    

    调用consume方法会持续的调用InputChannel的receiveMessage方法来从socket中读取数据。到这里,我们已经将写入socket的事件读出来了。

    public void registerInputChannel(InputChannel inputChannel,
                InputWindowHandle inputWindowHandle) {
       if (inputChannel == null) {
          throw new IllegalArgumentException("inputChannel must not be null.");
       }
       nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
    }
    

    nativeRegisterInputManger

    static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
            jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
        NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    
        sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
                inputChannelObj);
        if (inputChannel == NULL) {
            throwInputChannelNotInitialized(env);
            return;
        }
    
        sp<InputWindowHandle> inputWindowHandle =
                android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
    
        status_t status = im->registerInputChannel(
                env, inputChannel, inputWindowHandle, monitor);
        if (status) {
            String8 message;
            message.appendFormat("Failed to register input channel.  status=%d", status);
            jniThrowRuntimeException(env, message.string());
            return;
        }
    
        if (! monitor) {
            android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
                    handleInputChannelDisposed, im);
        }
    }
    

    NativeInputManager的registerInputChannel还会调用到InputDispatcher的registerInputChannel,会通过InputChannel创建相应的Connection,同时将InputChannel加入到相应的监控之中。在上面对代码的分析之中,获取InputChannel,就是通过这个Connection来获取的。

    status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
            const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
        { // acquire lock
            AutoMutex _l(mLock);
    
            if (getConnectionIndexLocked(inputChannel) >= 0) {
                return BAD_VALUE;
            }
    
            sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
    
            int fd = inputChannel->getFd();
            mConnectionsByFd.add(fd, connection);
    
            if (monitor) {
                mMonitoringChannels.push(inputChannel);
            }
    
            mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
        } // release lock
    
        // Wake the looper because some connections have changed.
        mLooper->wake();
        return OK;
    }
    

    ViewRootImpl

    事件在从socket读出之后,经过传递,最终会调用到ViewRootImpl的enqueueInputEvent方法。

    void enqueueInputEvent(InputEvent event,
                InputEventReceiver receiver, int flags, boolean processImmediately) {
         adjustInputEventForCompatibility(event);
         QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
    
         QueuedInputEvent last = mPendingInputEventTail;
         if (last == null) {
             mPendingInputEventHead = q;
             mPendingInputEventTail = q;
          } else {
              last.mNext = q;
              mPendingInputEventTail = q;
          }
          mPendingInputEventCount += 1;
    
          if (processImmediately) {
              doProcessInputEvents();
          } else {
              scheduleProcessInputEvents();
          }
     }
    

    enqueueInputEvent方法从InputEventReceiver中获取到InputEvent,然后将其加入到当前的事件队列之中,最后调用doProcessInputEvents来进行处理。

    void doProcessInputEvents() {
        while (mPendingInputEventHead != null) {
                QueuedInputEvent q = mPendingInputEventHead;
                mPendingInputEventHead = q.mNext;
                if (mPendingInputEventHead == null) {
                    mPendingInputEventTail = null;
                }
                q.mNext = null;
    
                mPendingInputEventCount -= 1;
          
                long eventTime = q.mEvent.getEventTimeNano();
                long oldestEventTime = eventTime;
                if (q.mEvent instanceof MotionEvent) {
                    MotionEvent me = (MotionEvent)q.mEvent;
                    if (me.getHistorySize() > 0) {
                        oldestEventTime = me.getHistoricalEventTimeNano(0);
                    }
                }
                mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
    
               deliverInputEvent(q);
            }
    
            // We are done processing all input events that we can process right now
            // so we can clear the pending flag immediately.
            if (mProcessInputEventsScheduled) {
                mProcessInputEventsScheduled = false;
                mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
            }
        }
    

    遍历所有的消息,如果事件类型为触摸屏事件,对其进行相应的时间修改,最后对于每一个处理完成的事件调用deliverInputEvent,

    private void deliverInputEvent(QueuedInputEvent q) {
         
         q.mEvent.getSequenceNumber());
         if (mInputEventConsistencyVerifier != null) {
             mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
          }
    
         InputStage stage;
         if (q.shouldSendToSynthesizer()) {
              stage = mSyntheticInputStage;
          } else {
              stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
          }
    
         if (stage != null) {
              stage.deliver(q);
          } else {
              finishInputEvent(q);
          }
     }
    

    在事件分发环节,首先进行事件的一个判断,通过shouldSkipIme来判断是否传递给输入法,然后决定使用何种InputStage进行消息的继续传递,这里实现了多种InputStage,对于每一个类型的InputStage都实现了一个方法process方法来针对不同类型的事件做处理,如果是触摸屏类的消息,最终会将事件的处理转交到View的身上。

    InputStage中的事件如何传递处理,传递处理之后,如何进行

    对于InputStage涉及的篇幅较多,这里也不再展开,当消息到达ViewRootImpl中后,接下来就是在View间的派发。

    View的事件派发

    对于View层的事件派发,我们最常见的就是dispatchTouchEventonTouch,onInterceptTouchEvent,onClickonTouchEvent等。对于View树上事件的派发,就是在对树的遍历传递中,主要起作用的就是这几个函数。这里我们先从View的相关事件函数开始分析,由于ViewGroup具有子View的原因,其相关的事件派发逻辑和View有所区别,这里我们先进行View的事件分析。

    public boolean dispatchTouchEvent(MotionEvent event) {
        ....
        if (onFilterTouchEventForSecurity(event)) {
              if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                    result = true;
                }
                //noinspection SimplifiableIfStatement
                ListenerInfo li = mListenerInfo;
                if (li != null && li.mOnTouchListener != null
                        && (mViewFlags & ENABLED_MASK) == ENABLED
                        && li.mOnTouchListener.onTouch(this, event)) {
                    result = true;
                }
    
                if (!result && onTouchEvent(event)) {
                    result = true;
                }
            }
        ....
        return result;
    }
    

    对于在View上的事件派发,核心操作是两点,一个是调用监听器的onTouch方法,然后判断事件是否被消耗,如果没有被消耗,则会调用onTouchEvent方法。在onTouchEvent中根据消息类型进行一些处理。
    根据事件类型来更新内部的一些状态。这里比较复杂的还是在ViewGroup中的事件分发逻辑,这里在分发的过程中,需要判断是否对事件进行拦截,如果不拦截,是否自身可处理,如果需要考虑到其中的子View。这里对其中的关键代码进行逐步分析。

    final boolean intercepted;
    if (actionMasked == MotionEvent.ACTION_DOWN
                        || mFirstTouchTarget != null) {
        final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
        if (!disallowIntercept) {
            intercepted = onInterceptTouchEvent(ev);
            ev.setAction(action); // restore action in case it was changed
        } else {
             intercepted = false;
        }
       } else {
            intercepted = true;
      }
    

    判断是否进行拦截,调用自身的onInterceptTouchEvent,开发者可以重载这个方法进行自己的一些操作。返回true表示拦截事件。如果要对事件进行拦截,则不再进行子View的遍历。否则将会进行子View的遍历,事件传递,在子View的事件传递结束之后,如果子View将事件消耗了则会将其加入到mFirstTouchTarget,如果遍历完成没有任何被添加

    if (mFirstTouchTarget == null) {
                    // No touch targets so treat this as an ordinary view.
                    handled = dispatchTransformedTouchEvent(ev, canceled, null,
                            TouchTarget.ALL_POINTER_IDS);
                } 
    

    接下来进行的是对于事件在子View中的派发,这里我们也只是针对其中的核心代码进行分析。

     final View[] children = mChildren;
     for (int i = childrenCount - 1; i >= 0; i--) {
           final int childIndex = getAndVerifyPreorderedIndex(
                                        childrenCount, i, customOrder);
           final View child = getAndVerifyPreorderedView(
                                        preorderedList, children, childIndex);
    
            ....
          dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign);
        ....
    }
    

    在对子View进行遍历的处理的时候,如果子View的事件被消耗,那么我们就会将其TouchTarget赋值给mFirstTouchTarget,当检测到mFirstTouchTarget为空时会再调用Viewgroup自身的dispatchTransformedTouchEvent方法,这个时候就会调用其onTouchEvent,然后继续View中的事件传递流程。

    if (mFirstTouchTarget == null) {
                    // No touch targets so treat this as an ordinary view.
        handled = dispatchTransformedTouchEvent(ev, canceled, null,
                            TouchTarget.ALL_POINTER_IDS);
     }
    

    对于dispatchTransformedTouchEvent函数

     private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
                View child, int desiredPointerIdBits) {
      if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
                event.setAction(MotionEvent.ACTION_CANCEL);
                if (child == null) {
                    handled = super.dispatchTouchEvent(event);
                } else {
                    handled = child.dispatchTouchEvent(event);
                }
                event.setAction(oldAction);
                return handled;
            }
        ....  
    }
    

    这里事件的派发也是在调用了每一个子View的dispatchTouchEvent方法,根据返回结果来判断是否被消耗,一旦事件被消耗则会停止传递。

    相关文章

      网友评论

        本文标题:Android系统源码剖析-事件分发

        本文链接:https://www.haomeiwen.com/subject/jiimnxtx.html