Android系統(tǒng)源碼剖析-事件分發(fā)

前言

上一篇文章中,對(duì)于事件的監(jiān)控和獲取做了分析,在拿到事件之后,后續(xù)是如何處理分發(fā)的呢?本篇文章主要針對(duì)在通過getEvent獲取到事件之后,后續(xù)的相關(guān)分發(fā)處理流程。

事件處理分發(fā)

InputReaderThread函數(shù)不斷地調(diào)用looperOnce函數(shù),不斷的從中讀取事件,那么下一個(gè)問題來了,讀取到事件要放置到哪里,又在哪里被消耗掉了呢?也就是事件接下來的流向問題。讓我們回到looperOnce之前。

事件分發(fā)

processEventsLocked

在調(diào)用了getEvent之后,獲得了事件之后,接著調(diào)用了相應(yīng)的處理函數(shù)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;
    }
}

首先對(duì)于事件類型進(jìn)行了判斷,如果事件不是合成事件,則會(huì)對(duì)其DeviceID進(jìn)行判斷,通過對(duì)其判斷來確定batchSize等,如果是合成事件,則會(huì)具體判斷,判斷是設(shè)備的添加,設(shè)備的移除,完成設(shè)備掃描等等,然后對(duì)事件分別進(jìn)行處理,這里我們只關(guān)心對(duì)于設(shè)備自身產(chǎn)生的事件。也就是觸摸屏相關(guān)的事件。也就是processEventsForDeviceLocked函數(shù)中所進(jìn)行的操作。

事件派發(fā)到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);
}

根據(jù)事件獲得相應(yīng)的設(shè)備類型,然后將事件交給相應(yīng)的設(shè)備處理。判斷是否忽略該事件,如果不是忽略該事件,則會(huì)調(diào)用相應(yīng)設(shè)備的process方法進(jìn)行處理。

事件派發(fā)到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對(duì)應(yīng)了很多的子類,這里根據(jù)事件的類型進(jìn)行相應(yīng)的派發(fā),處理。事件到了這里之后,這里來看一下對(duì)于觸摸屏事件的處理的相關(guān)類和處理函數(shù)。

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

通過這里的函數(shù)處理,我們繼續(xù)追蹤函數(shù)的數(shù)據(jù)流向。對(duì)于相關(guān)事件會(huì)調(diào)用TouchInputMapper的sync方法來進(jìn)行處理。

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

void TouchInputMapper::processRawTouches(bool timeout) {
        ....
        cookAndDispatch(mCurrentRawState.when);
        ....
}

在相關(guān)的函數(shù)調(diào)用之后,最終調(diào)用了dispatchTouches

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

對(duì)于dispatchTouches中,會(huì)根據(jù)記錄的上一次的觸摸位置,對(duì)事件的類型進(jìn)行判斷,然后做相應(yīng)的分發(fā),事件類型有抬起,下落,移動(dòng)等,然后對(duì)相應(yīng)的事件進(jìn)行分發(fā)。無論是對(duì)于何種類型的事件派發(fā),最終被調(diào)用到的都是dispatchMotion()方法。

對(duì)于相關(guān)事件的分發(fā)最終調(diào)用到了dispatchMotion(),對(duì)事件數(shù)據(jù)進(jìn)行組裝之后,調(diào)用了

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

這里對(duì)于事件進(jìn)行了封裝,構(gòu)造出一個(gè)NotifyMotionArgs,在整個(gè)傳遞流程做的比較多的就是通過對(duì)于事件進(jìn)行一系列的判斷,然后進(jìn)行一系列的封裝。接下來的執(zhí)行是調(diào)用QueuedInputListener的notifyMotion,將構(gòu)造的事件添加到其中的一個(gè)Args隊(duì)列之中。

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

notifyMotion函數(shù)實(shí)現(xiàn)

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

之后又調(diào)用了QueuedInputListenerflush方法。遍歷事件的隊(duì)列,然后對(duì)其逐一調(diào)用notify函數(shù)。

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函數(shù)實(shí)現(xiàn)

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

對(duì)于這個(gè)listener的創(chuàng)建來自于InputReader構(gòu)建的時(shí)候。

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

而這里的Listener則是InputDispatcher,InputDispatcher 的notifyMotion實(shí)現(xiàn)源碼。

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

在該函數(shù)中,所做的事情是對(duì)于所傳遞的參數(shù),構(gòu)造MotionEntry,然后將其加入到enqueueInboundEventLocked之中。然后喚醒其中的looper。

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    bool needWake = mInboundQueue.isEmpty();
    mInboundQueue.enqueueAtTail(entry);
    ...
    //進(jìn)行一些事件和窗口相關(guān)的判斷處理
}

Dispatcher開啟的線程中,每次循環(huán)的操作如何?

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

Dispatcher下dispatchOnce的實(shí)現(xiàn)

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中,獲取到事件,然后對(duì)事件類型進(jìn)行判斷,判斷之后調(diào)用了dispatchMotionLocked函數(shù),來繼續(xù)進(jìn)行事件的傳遞。

bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
      ....
      Vector<InputTarget> inputTargets;
if (isPointerEvent) {
        // Pointer event.  (eg. touchscreen)
      //尋找目標(biāo)窗口
        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);
        } 
    }
}

獲得目標(biāo)輸入,根據(jù)InputChannel獲取相應(yīng)的連接,然后調(diào)用prepareDispatchCycleLocked(),進(jìn)行事件的派發(fā)。
enqueueDispatchEntriesLocked,在該方法中又調(diào)用了startDispatchCycleLocked方法。其實(shí)現(xiàn)為

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;
    }
    ....
   }
    ...
}

至此調(diào)用了connection 的inputPublisher的publishMotionEvent方法將事件分發(fā)消耗。

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

該方法所執(zhí)行的操作是利用傳入的觸摸信息,構(gòu)建點(diǎn)擊消息,然后通過InputChannel將消息發(fā)送出去。這里引出了InputChannel,在此,我們通InputPublisher的創(chuàng)建反推出InputChannel是何時(shí)被引入的,何時(shí)被創(chuàng)建的。從而進(jìn)一步分析其作用。在分析之前先讓我們來對(duì)上述的分析過程做一個(gè)總結(jié)。

觸摸事件讀取分發(fā)過程

ReaderThread開啟后會(huì)從EventHub中輪詢獲取時(shí)間,獲取到事件之后,將進(jìn)行一系列的處理,對(duì)事件進(jìn)行加工包裝,然后傳遞給相應(yīng)的InputDevice,InputMapper,然后將包裝的事件添加到一個(gè)事件隊(duì)列中,InputDispatcher的線程則會(huì)在輪詢讀取該線程中的事件,然后將其再次進(jìn)行做判斷處理后,傳遞,最終到達(dá)InputChannel,通過InputChannel,來將數(shù)據(jù)發(fā)送出去。

事件產(chǎn)生讀取分發(fā)

到此,對(duì)于輸入事件,我們已經(jīng)分析到了InputChannel,對(duì)于其上的具體分析轉(zhuǎn)化,將是接下來分析的核心。

InputChannel

從上面分析可以看到事件傳遞部分最后是通過InputChannel所發(fā)送出去的,那么InputChannel是在何時(shí)被創(chuàng)建的呢?何時(shí)被InputManager所使用的呢?同時(shí),對(duì)于InputReaderThread和InputDispatcherThread是運(yùn)行在SystemServer進(jìn)程中的,而我們的應(yīng)用進(jìn)程是和其不在同一個(gè)進(jìn)程中的。這之間一定也是有進(jìn)程間的通信機(jī)制在里面。具體是如何實(shí)現(xiàn)的呢?這里我們從InputChannel的創(chuàng)建著手來看。

InputChannel的創(chuàng)建是在 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);
  ....
}

這里對(duì)于ViewRootImpl和WindowSession相關(guān)暫且不介紹,對(duì)于這方面的知識(shí),需要很大的篇幅來介紹,這里先只是講到是在這里創(chuàng)建的,對(duì)于其相關(guān)的內(nèi)容將在后續(xù)的文章中介紹。這里首先是創(chuàng)建了一個(gè)InputChannel,然后將其調(diào)用了WindowSessionaddToDisplay方法將其作為參數(shù)傳遞。

public InputChannel() {
}

在InputChannel中的方法都為調(diào)用了相應(yīng)的native方法。這里調(diào)用的addToDisplay將會(huì)把InputChannel添加到WindowManagerService中。會(huì)調(diào)用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);
      }
      ....
}

對(duì)于InputChannel的相關(guān)處理調(diào)用了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);
}

首先調(diào)用了InputChannel的openInputChannelPair方法,該方法調(diào)用了InputChannel的native方法nativeOpenInputChannelPair,創(chuàng)建了兩個(gè)InputChannel,對(duì)其中一個(gè)通過InputManager進(jìn)行了InputChannel的注冊(cè)。對(duì)于InputChannel的相關(guān)Native的實(shí)現(xiàn)是在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;
}

接收端的消息由誰來觸發(fā)呢?是如何觸發(fā)開始接受消息,消息如何在傳到InputChannel之后,進(jìn)行的進(jìn)一步的數(shù)據(jù)傳遞呢?這是接下來所要去分析的,這里先對(duì)上面InputChannel進(jìn)行一個(gè)總結(jié)。

InputChannel數(shù)據(jù)傳輸

之前的setView中,我們創(chuàng)建了InputChannel之后,開啟了對(duì)于InputChannel中輸入事件的監(jiān)聽。

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

WindowInputEventReceiver的構(gòu)造函數(shù)如下,其繼承自InputEventReceiver。

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

InputEventReceiver的構(gòu)造函數(shù)源碼如下

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

這里調(diào)用了native方法來做初始化,相關(guān)的native方法的實(shí)現(xiàn)在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();
  .....
}

根據(jù)傳入的InputChannelMessageQueue,創(chuàng)建一個(gè)NativeInputEventReceiver,然后調(diào)用其initialize方法。

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

initialize()方法中,只調(diào)用了一個(gè)函數(shù)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,然后調(diào)用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的實(shí)現(xiàn)如下

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

該方法所執(zhí)行的操作就是對(duì)傳遞的fd添加epoll監(jiān)控,Looper會(huì)循環(huán)調(diào)用pollOnce方法,而pollOnce方法的核心實(shí)現(xiàn)就是pollInner。其代碼大致實(shí)現(xiàn)內(nèi)容為等待消息的到來,當(dāng)有消息到來后,根據(jù)消息類型做一些判斷處理,然后調(diào)用其相關(guān)的callback。我們當(dāng)前是對(duì)于開啟的socket的一個(gè)監(jiān)聽,當(dāng)有數(shù)據(jù)到來,我們便會(huì)執(zhí)行相應(yīng)的回調(diào)。這里對(duì)于InputChannel的回調(diào)是在調(diào)用了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;
}

對(duì)于Event的處理,這里調(diào)用consumeEvents來對(duì)事件進(jìn)行處理。

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

調(diào)用consume方法會(huì)持續(xù)的調(diào)用InputChannel的receiveMessage方法來從socket中讀取數(shù)據(jù)。到這里,我們已經(jīng)將寫入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還會(huì)調(diào)用到InputDispatcher的registerInputChannel,會(huì)通過InputChannel創(chuàng)建相應(yīng)的Connection,同時(shí)將InputChannel加入到相應(yīng)的監(jiān)控之中。在上面對(duì)代碼的分析之中,獲取InputChannel,就是通過這個(gè)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讀出之后,經(jīng)過傳遞,最終會(huì)調(diào)用到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,然后將其加入到當(dāng)前的事件隊(duì)列之中,最后調(diào)用doProcessInputEvents來進(jìn)行處理。

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

遍歷所有的消息,如果事件類型為觸摸屏事件,對(duì)其進(jìn)行相應(yīng)的時(shí)間修改,最后對(duì)于每一個(gè)處理完成的事件調(diào)用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);
      }
 }

在事件分發(fā)環(huán)節(jié),首先進(jìn)行事件的一個(gè)判斷,通過shouldSkipIme來判斷是否傳遞給輸入法,然后決定使用何種InputStage進(jìn)行消息的繼續(xù)傳遞,這里實(shí)現(xiàn)了多種InputStage,對(duì)于每一個(gè)類型的InputStage都實(shí)現(xiàn)了一個(gè)方法process方法來針對(duì)不同類型的事件做處理,如果是觸摸屏類的消息,最終會(huì)將事件的處理轉(zhuǎn)交到View的身上。

InputStage中的事件如何傳遞處理,傳遞處理之后,如何進(jìn)行

對(duì)于InputStage涉及的篇幅較多,這里也不再展開,當(dāng)消息到達(dá)ViewRootImpl中后,接下來就是在View間的派發(fā)。

View的事件派發(fā)

對(duì)于View層的事件派發(fā),我們最常見的就是dispatchTouchEvent,onTouch,onInterceptTouchEvent,onClick,onTouchEvent等。對(duì)于View樹上事件的派發(fā),就是在對(duì)樹的遍歷傳遞中,主要起作用的就是這幾個(gè)函數(shù)。這里我們先從View的相關(guān)事件函數(shù)開始分析,由于ViewGroup具有子View的原因,其相關(guān)的事件派發(fā)邏輯和View有所區(qū)別,這里我們先進(jìn)行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;
}

對(duì)于在View上的事件派發(fā),核心操作是兩點(diǎn),一個(gè)是調(diào)用監(jiān)聽器的onTouch方法,然后判斷事件是否被消耗,如果沒有被消耗,則會(huì)調(diào)用onTouchEvent方法。在onTouchEvent中根據(jù)消息類型進(jìn)行一些處理。
根據(jù)事件類型來更新內(nèi)部的一些狀態(tài)。這里比較復(fù)雜的還是在ViewGroup中的事件分發(fā)邏輯,這里在分發(fā)的過程中,需要判斷是否對(duì)事件進(jìn)行攔截,如果不攔截,是否自身可處理,如果需要考慮到其中的子View。這里對(duì)其中的關(guān)鍵代碼進(jìn)行逐步分析。

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

判斷是否進(jìn)行攔截,調(diào)用自身的onInterceptTouchEvent,開發(fā)者可以重載這個(gè)方法進(jìn)行自己的一些操作。返回true表示攔截事件。如果要對(duì)事件進(jìn)行攔截,則不再進(jìn)行子View的遍歷。否則將會(huì)進(jìn)行子View的遍歷,事件傳遞,在子View的事件傳遞結(jié)束之后,如果子View將事件消耗了則會(huì)將其加入到mFirstTouchTarget,如果遍歷完成沒有任何被添加

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

接下來進(jìn)行的是對(duì)于事件在子View中的派發(fā),這里我們也只是針對(duì)其中的核心代碼進(jìn)行分析。

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

在對(duì)子View進(jìn)行遍歷的處理的時(shí)候,如果子View的事件被消耗,那么我們就會(huì)將其TouchTarget賦值給mFirstTouchTarget,當(dāng)檢測(cè)到mFirstTouchTarget為空時(shí)會(huì)再調(diào)用Viewgroup自身的dispatchTransformedTouchEvent方法,這個(gè)時(shí)候就會(huì)調(diào)用其onTouchEvent,然后繼續(xù)View中的事件傳遞流程。

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

對(duì)于dispatchTransformedTouchEvent函數(shù)

 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;
        }
    ....  
}

這里事件的派發(fā)也是在調(diào)用了每一個(gè)子View的dispatchTouchEvent方法,根據(jù)返回結(jié)果來判斷是否被消耗,一旦事件被消耗則會(huì)停止傳遞。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 序言 最近在看Android觸摸屏事件相關(guān)的源碼,為了對(duì)整個(gè)事件體系的了解,所以對(duì)事件相關(guān),從事件的產(chǎn)生,寫入設(shè)備...
    Jensen95閱讀 805評(píng)論 0 3
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,790評(píng)論 25 709
  • 要求:不僅僅能實(shí)現(xiàn)相應(yīng)的功能,還需要保證代碼的魯棒性,并且能夠分析代碼的空間復(fù)雜度和時(shí)間復(fù)雜度。 二維數(shù)組中的查找...
    二十四橋客_閱讀 1,013評(píng)論 0 1
  • 我的味蕾被提醒 下班回家的方向飛行 期待在車輪外圈歡騰 似乎在計(jì)算彼此心房的里程 纏繞在睫毛的白色蒸發(fā)了又結(jié)晶 視...
    李譯閱讀 932評(píng)論 2 7
  • 華姐,是我們一個(gè)案子的當(dāng)事人。 第一次見她,是在事務(wù)所,當(dāng)時(shí)說好我去幫她調(diào)查取證來著。 太遠(yuǎn),其實(shí)我不想去。 一 ...
    琴人彌茶閱讀 573評(píng)論 0 2

友情鏈接更多精彩內(nèi)容