Android Input輸入事件處理流程分享(2)

努比亞技術(shù)團(tuán)隊(duì)原創(chuàng)內(nèi)容枢劝,轉(zhuǎn)載請務(wù)必注明出處。

  • Native層傳遞過程
    • InputEventReceiver的事件來源于哪里
    • InputConsumer
      • InputConsumer處理事件
      • InputConsumer的構(gòu)建
    • InputChannel
      • InputChannel的創(chuàng)建
      • server端InputChannel的注冊
      • client端InputChannel讀取事件并傳遞
      • 小結(jié)
    • InputManagerService
      • IMS的創(chuàng)建
      • IMS的啟動
      • 小結(jié)
    • InputDispatcher
      • InputDispatcher啟動
      • InputDispatcher分發(fā)事件
    • InputReader(InputDispatcher事件的來源)
      • InputReader啟動
      • InputReader處理事件
    • EventHub
      • EventHub的創(chuàng)建
      • EventHub如何獲取輸入事件
        • EventHub處理reopen設(shè)備
        • EventHub處理close設(shè)備
        • EventHub掃描設(shè)備
        • EventHub處理open設(shè)備
        • EventHub處理event
        • EventHub處理inotify事件
      • 小結(jié)

Native層傳遞過程

此小節(jié)主要介紹輸入事件是如何從InputReader獲取卜壕,然后InputDispatcher又是如何將它們分發(fā)出去您旁,這個過程中使用什么技術(shù)進(jìn)行事件的傳遞的。

Natvie事件傳遞時序圖

InputEventReceiver的事件來源于哪里

上節(jié)中有介紹在Native層NativeInputEventReceiver的consumeEvents方法中會通過jni方式調(diào)用Java層的InputEventReceiver的dispatchInputEvent方法將事件傳遞到上層轴捎。那consumeEvents的事件又來源于哪里呢鹤盒?我們繼續(xù)看這個consumeEvents方法。

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
    // 省略若干行
    for (;;) {
        // 省略若干行
        InputEvent* inputEvent;
        // 這里調(diào)用了InputConsumer的consume方法來獲取輸入事件
        status_t status = mInputConsumer.consume(&mInputEventFactory,
                consumeBatches, frameTime, &seq, &inputEvent,
                &motionEventType, &touchMoveNum, &flag);
        // 省略若干行
        if (skipCallbacks) {
            mInputConsumer.sendFinishedSignal(seq, false);
        }
    }
}

InputConsumer

consume方法中主要是從InputChannel獲取輸入事件的信息侦副,然后根據(jù)消息中獲取的事件類型構(gòu)造出對應(yīng)的event侦锯,并將消息中的事件信息賦值給event對象。

InputConsumer處理事件

從上面分析我們能夠看到秦驯,再NativeInputEventReceiver的consumeEvents方法中尺碰,會循環(huán)調(diào)用InputConsumer的consume方法獲取事件并進(jìn)行處理。InputConsumer的consume方法中會通過InputChannel從socket中通過recv系統(tǒng)調(diào)用獲取下層傳遞的事件译隘,獲取到事件后就會通過jni向Java層傳遞亲桥。

InputConsumer處理事件
status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches,
                                nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
                                int* motionEventType, int* touchMoveNumber, bool* flag) {
    // 省略若干行
    *outSeq = 0;
    *outEvent = nullptr;
    // Fetch the next input message.
    // Loop until an event can be returned or no additional events are received.
    while (!*outEvent) {
        if (mMsgDeferred) {
            // mMsg contains a valid input message from the previous call to consume
            // that has not yet been processed.
            mMsgDeferred = false;
        } else {
            // Receive a fresh message.
            // 這里通過調(diào)用InputChannel的receiveMessage來獲取消息
            status_t result = mChannel->receiveMessage(&mMsg);
            // 省略若干行
        }
        // 根據(jù)消息的類型生成不同的Event
        switch (mMsg.header.type) {
            case InputMessage::Type::KEY: {
                // 構(gòu)造一個KeyEvent
                KeyEvent* keyEvent = factory->createKeyEvent();
                if (!keyEvent) return NO_MEMORY;
                // 從msg中獲取事件的各屬性,并賦值給構(gòu)造出的Event對象
                initializeKeyEvent(keyEvent, &mMsg);
                *outSeq = mMsg.body.key.seq;
                *outEvent = keyEvent;
                if (DEBUG_TRANSPORT_ACTIONS) {
                    ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
                          mChannel->getName().c_str(), *outSeq);
                }
            break;
            }
  
            case InputMessage::Type::MOTION: {
                // 構(gòu)造一個MotionEvent
                MotionEvent* motionEvent = factory->createMotionEvent();
                if (!motionEvent) return NO_MEMORY;
                updateTouchState(mMsg);
                // 從msg中獲取事件的各屬性固耘,并賦值給構(gòu)造出的Event對象
                initializeMotionEvent(motionEvent, &mMsg);
                *outSeq = mMsg.body.motion.seq;
                *outEvent = motionEvent;
  
                if (DEBUG_TRANSPORT_ACTIONS) {
                    ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
                          mChannel->getName().c_str(), *outSeq);
                }
                break;
            }
            // 省略若干行
  
        }
    }
    return OK;
}

這里我們先看下event的構(gòu)造和初始化题篷,輸入消息的獲取隨后再介紹。先看下factory->createMotionEvent玻驻,這里factory是PreallocatedInputEventFactory的實(shí)例悼凑。

class PreallocatedInputEventFactory : public InputEventFactoryInterface {
public:
    PreallocatedInputEventFactory() { }
    virtual ~PreallocatedInputEventFactory() { }
    // 可以看到這里返回的是全局變量的地址
    virtual KeyEvent* createKeyEvent() override { return &mKeyEvent; }
    virtual MotionEvent* createMotionEvent() override { return &mMotionEvent; }
    virtual FocusEvent* createFocusEvent() override { return &mFocusEvent; }
  
private:
    // 這里定義不同類型的事件變量
    KeyEvent mKeyEvent;
    MotionEvent mMotionEvent;
    FocusEvent mFocusEvent;
};

好了,我們繼續(xù)看event的初始化璧瞬。這里主要是從msg中獲取對應(yīng)事件的詳細(xì)信息然后賦值給對應(yīng)的event對象上户辫。

// 對key事件進(jìn)行初始化
void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
    event->initialize(msg->body.key.eventId, msg->body.key.deviceId, msg->body.key.source,
                      msg->body.key.displayId, msg->body.key.hmac, msg->body.key.action,
                      msg->body.key.flags, msg->body.key.keyCode, msg->body.key.scanCode,
                      msg->body.key.metaState, msg->body.key.repeatCount, msg->body.key.downTime,
                      msg->body.key.eventTime);
}
  
// 對motion事件進(jìn)行初始化
void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
    // 省略若干行
    event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source,
                      msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action,
                      msg->body.motion.actionButton, msg->body.motion.flags,
                      msg->body.motion.edgeFlags, msg->body.motion.metaState,
                      msg->body.motion.buttonState, msg->body.motion.classification,
                      msg->body.motion.xScale, msg->body.motion.yScale, msg->body.motion.xOffset,
                      msg->body.motion.yOffset, msg->body.motion.xPrecision,
                      msg->body.motion.yPrecision, msg->body.motion.xCursorPosition,
                      msg->body.motion.yCursorPosition, msg->body.motion.downTime,
                      msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords);
}

然后我們繼續(xù)看msg的獲取方法:InputChannel的receiveMessage方法。

status_t InputChannel::receiveMessage(InputMessage* msg) {
    ssize_t nRead;
    do {
        // 這里通過recv系統(tǒng)調(diào)用從socket中讀取消息
        nRead = ::recv(mFd.get(), msg, sizeof(InputMessage), MSG_DONTWAIT);
    } while (nRead == -1 && errno == EINTR);
    // 省略若干行
    return OK;
}

可以看到這個方法主要是從socket中讀取消息嗤锉。那這里的socket是什么時候建立的呢渔欢?我們繼續(xù)向下看。

InputConsumer的構(gòu)建

在NativeInputEventReceiver的構(gòu)造方法中瘟忱,會創(chuàng)建出NativeInputEventReceiver奥额,并將InputChannel傳入苫幢。而NativeInputEventReceiver的構(gòu)建是在Java層InputEventReceiver的native方法nativeInit中創(chuàng)建,并且能夠看到垫挨,這里的InputChannel是從Java層傳遞下來的韩肝。

InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
        mResampleTouch(isTouchResamplingEnabled()),
        // 初始化InputChannel
        mChannel(channel), mMsgDeferred(false) {
}

我們發(fā)現(xiàn)在InputConsumer構(gòu)造時對InputChannel進(jìn)行了初始化,那就繼續(xù)超前看InputConsumer在哪里構(gòu)建的九榔。

NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
        jobject receiverWeak, const sp<InputChannel>& inputChannel,
        const sp<MessageQueue>& messageQueue) :
        mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
        mInputConsumer(inputChannel), mMessageQueue(messageQueue),
        mBatchedInputEventPending(false), mFdEvents(0) {
    if (kDebugDispatchCycle) {
        ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName().c_str());
    }
}

回到NativeInputEventReceiver中哀峻,發(fā)現(xiàn)它的構(gòu)造方法中傳入了InputChannel,那么繼續(xù)看NativeInputEventReceiver的構(gòu)建哲泊。

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    // 通過jni獲取java創(chuàng)建的InputChannel
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    // 省略若干行
    // 構(gòu)建出NativeInputEventReceiver
    sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    // 初始化Receiver
    status_t status = receiver->initialize();
    // 省略若干行
    receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
    return reinterpret_cast<jlong>(receiver.get());
}

通過上述分析剩蟀,我們發(fā)現(xiàn)NativeInputEventReceiver中獲取底層事件的InputChannel是來自于Java層的傳遞,那么切威,InputChannel又是如何創(chuàng)建的呢育特?

InputChannel

InputChannel會作為句柄傳遞到下層,后面分發(fā)事件的時候會通過它來進(jìn)行先朦。而且這里會創(chuàng)建出兩個缰冤,一個作為server端注冊到InputManagerService,最終會注冊到InputDispatcher中去喳魏,另一個則作為client端來接收server端的事件锋谐。

InputChannel的創(chuàng)建

通過前面分析,我們發(fā)現(xiàn)NativeInputEventReceiver中的InputChanel來源于Java層的InputChannel截酷。上述nativeInit是Java層InputEventReceiver的native方法涮拗,繼續(xù)看Java層的InputEventReceiver。

InputChannel的創(chuàng)建
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
    // 省略若干行
    mInputChannel = inputChannel;
    mMessageQueue = looper.getQueue();
    // 將Java層的inputChannel向下層傳遞
    mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
            inputChannel, mMessageQueue);
    mCloseGuard.open("dispose");
}

Java層InputEventReceiver構(gòu)造時傳入了InputChannel迂苛。在ViewRootImpl的setView方法中會創(chuàng)建InputChannel三热,然后會調(diào)用Session的addToDisplayAsUser方法初始化InputChannel

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {
    synchronized (this) {
        if (mView == null) {
            // 省略若干行
            InputChannel inputChannel = null;
            if ((mWindowAttributes.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                inputChannel = new InputChannel();
            }
            // 省略若干行
            // 調(diào)用Session的addToDisplayAsUser方法來添加window,
            // 會初始化InputChannel
            res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                    getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                    mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                    mAttachInfo.mDisplayCutout, inputChannel,
                    mTempInsets, mTempControls);
            // 省略若干行
            if (inputChannel != null) {
                if (mInputQueueCallback != null) {
                    mInputQueue = new InputQueue();
                    mInputQueueCallback.onInputQueueCreated(mInputQueue);
                }
                // 將InputChannel傳入InputEventReceiver
                mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                        Looper.myLooper());
            }
            // 省略若干行
        }
    }
}

Session的addToDisplayAsUser方法會繼續(xù)調(diào)用WindowManagerService的addWindow方法三幻。

public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, int userId, Rect outFrame,
        Rect outContentInsets, Rect outStableInsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
        InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
    // 直接調(diào)用WindowManagerService的addWindow方法
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
            outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
            outInsetsState, outActiveControls, userId);
}

addWindow方法中會調(diào)用WindowState打開InputChannel就漾。

public int addWindow(Session session, IWindow client, int seq,
        LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
        Rect outContentInsets, Rect outStableInsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
        InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
        int requestUserId) {
    // 省略若干行
    final WindowState win = new WindowState(this, session, client, token, parentWindow,
            appOp[0], seq, attrs, viewVisibility, session.mUid, userId,
            session.mCanAddInternalSystemWindow);
    // 省略若干行
    final boolean openInputChannels = (outInputChannel != null
            && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
    if  (openInputChannels) {
        // 這里會調(diào)用WindowState的openInputChannel來打開inputChannel
        win.openInputChannel(outInputChannel);
    }
    // 省略若干行
    return res;
}

繼續(xù)看WindowState的openInputChannel方法。首先會通過調(diào)用InputChannel的靜態(tài)方法openInputChannelPair來創(chuàng)建兩個InputChannel念搬,一個作為client一個作為server抑堡;然后還會調(diào)用InputManagerService的registerInputChannel來注冊server端的InputChannel;最后將client端的InputChannel設(shè)置到outInputChannel中朗徊。

void openInputChannel(InputChannel outInputChannel) {
    if (mInputChannel != null) {
        throw new IllegalStateException("Window already has an input channel.");
    }
    String name = getName();
    // 通過openInputChannelPair方法創(chuàng)建出兩個InputChannel
    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
    mInputChannel = inputChannels[0];
    mClientChannel = inputChannels[1];
    // 注冊server端的InputChannel到InputManagerService中
    mWmService.mInputManager.registerInputChannel(mInputChannel);
    mInputWindowHandle.token = mInputChannel.getToken();
    if (outInputChannel != null) {
        // 將client端的InputChannel設(shè)置到outInputChannel
        mClientChannel.transferTo(outInputChannel);
        mClientChannel.dispose();
        mClientChannel = null;
    } else {
        // If the window died visible, we setup a dummy input channel, so that taps
        // can still detected by input monitor channel, and we can relaunch the app.
        // Create dummy event receiver that simply reports all events as handled.
        mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
    }
    mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this);
}

上述openInputChannelPair方法中會直接調(diào)用InputChannel的native方法nativeOpenInputChannelPair來創(chuàng)建出一對InputChannel首妖。

public static InputChannel[] openInputChannelPair(String name) {
    if (name == null) {
        throw new IllegalArgumentException("name must not be null");
    }
  
    if (DEBUG) {
        Slog.d(TAG, "Opening input channel pair '" + name + "'");
    }
    // 繼續(xù)調(diào)用natvie方法創(chuàng)建出兩個InputChannel
    return nativeOpenInputChannelPair(name);
}

jni方法nativeOpenInputChannelPair中會繼續(xù)調(diào)用InputChannel的openInputChannelPair靜態(tài)方法。然后將創(chuàng)建出的兩個inputChannel分別添加到數(shù)組中爷恳,然后返回給上層有缆。

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    ScopedUtfChars nameChars(env, nameObj);
    std::string name = nameChars.c_str();
  
    sp<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    // 創(chuàng)建出server端和client端的InputChannel
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
    // 省略若干行
    // 添加到數(shù)組中,然后返回給上層
    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

openInputChannelPair方法中會首先通過socketpair創(chuàng)建一對相互連接的套接字,然后分別給socket設(shè)置相應(yīng)的選項(xiàng)值棚壁;然后通過InputChannel的create方法創(chuàng)建出兩個分別與socket關(guān)聯(lián)的inuptChannel杯矩。

status_t InputChannel::openInputChannelPair(const std::string& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    // 創(chuàng)建一對相互連接的socket
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        status_t result = -errno;
        // 創(chuàng)建失敗做相應(yīng)的處理
        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
                name.c_str(), errno);
        outServerChannel.clear();
        outClientChannel.clear();
        return result;
    }
  
    // 分別設(shè)置兩個socket的可讀可寫buffer
    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));
  
    sp<IBinder> token = new BBinder();
  
    std::string serverChannelName = name + " (server)";
    android::base::unique_fd serverFd(sockets[0]);
    // 創(chuàng)建出server端InputChannel,并于socket關(guān)聯(lián)
    outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);
  
    std::string clientChannelName = name + " (client)";
    android::base::unique_fd clientFd(sockets[1]);
    // 創(chuàng)建出client端InputChannel袖外,并于socket關(guān)聯(lián)
    outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
    return OK;
}

通過InputChannel的create方法構(gòu)建出InputChannel并返回史隆。

sp<InputChannel> InputChannel::create(const std::string& name, android::base::unique_fd fd,
                                      sp<IBinder> token) {
    // 設(shè)置文件描述符fd的狀態(tài)屬性為O_NONBLOCK
    const int result = fcntl(fd, F_SETFL, O_NONBLOCK);
    if (result != 0) {
        LOG_ALWAYS_FATAL("channel '%s' ~ Could not make socket non-blocking: %s", name.c_str(),
                         strerror(errno));
        return nullptr;
    }
    // 創(chuàng)建出InputChannel并返回
    return new InputChannel(name, std::move(fd), token);
}

至此,InputChannel便創(chuàng)建并關(guān)聯(lián)上socket上了曼验。并且通過前面的介紹逆害,我們知道了獲取輸入事件時是從client端的socket中讀取消息并進(jìn)行事件封裝,然后傳遞到上層蚣驼。但是這里我們發(fā)現(xiàn)有一個問題展哭,就是client端socket中的數(shù)據(jù)是從哪里來的呢票腰?我們繼續(xù)看一下WindowState的openInputChannel方法。

server端InputChannel的注冊

在通過openInputChannel開啟InputChannel后政溃,會調(diào)用了InputManagerService的registerInputChannel方法注冊server端的InputChannel

server端InputChannel的注冊
void openInputChannel(InputChannel outInputChannel) {
    // 省略若干行
    // 通過openInputChannelPair方法創(chuàng)建出兩個InputChannel
    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
    mInputChannel = inputChannels[0];
    mClientChannel = inputChannels[1];
    // 注冊server端的InputChannel到InputManagerService中
    mWmService.mInputManager.registerInputChannel(mInputChannel);
    // 省略若干行
}

我們發(fā)現(xiàn)server端的InputChannel被注冊到了InputManagerService中去了坛芽,那么留储,我們繼續(xù)向下看。

public void registerInputChannel(InputChannel inputChannel) {
    if (inputChannel == null) {
        throw new IllegalArgumentException("inputChannel must not be null.");
    }
    // 調(diào)用native方法繼續(xù)注冊
    nativeRegisterInputChannel(mPtr, inputChannel);
}

在InputManagerService的registerInputChannel方法中直接調(diào)用了native方法nativeRegisterInputChannel咙轩,我們繼續(xù)获讳。

static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputChannelObj) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    // 獲取InputChannel
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == nullptr) {
        throwInputChannelNotInitialized(env);
        return;
    }
    // 將inputChannel注冊到NativeInputManager中
    status_t status = im->registerInputChannel(env, inputChannel);
    // 設(shè)置dispose的callback,在inputChannel
    // dispose之后會調(diào)用函數(shù)指針handleInputChannelDisposed
    // 來調(diào)用NativeInputManager的unregisterInputChannel
    // 解注冊inputChannel
    android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
            handleInputChannelDisposed, im);
}

在native方法中活喊,先調(diào)用了NativeInputManager的registerInputChannel方法注冊inputChannel丐膝,然后會給inputChannel設(shè)置dispose callback,并且callback中執(zhí)行了inputChannel的解注冊钾菊。在NativeInputManager的registerInputChannel方法中帅矗,會獲取InputDispatcher,并將inputChannel注冊到其中去煞烫。

status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
        const sp<InputChannel>& inputChannel) {
    ATRACE_CALL();
    return mInputManager->getDispatcher()->registerInputChannel(inputChannel);
}

在InputDispatcher的registerInputChannel方法中浑此,會通過InputChannel構(gòu)建出Connection,然后將其添加到注冊列表當(dāng)中滞详。

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
#if DEBUG_REGISTRATION
    ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
#endif
  
    { // acquire lock
        std::scoped_lock _l(mLock);
        // 省略若干行
        // 創(chuàng)建connection并添加的注冊列表中
        sp<Connection> connection = new Connection(inputChannel, false /*monitor*/, mIdGenerator);
        int fd = inputChannel->getFd();
        mConnectionsByFd[fd] = connection;
        mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel;
        // 將inputChannel的fd添加到looper中凛俱,并且對應(yīng)的event是ALOOPER_EVENT_INPUT
        // 傳入的looper callback為handleReceiveCallback方法,
        // 因此當(dāng)事件到來時料饥,會觸發(fā)此callback
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock
  
    // Wake the looper because some connections have changed.
    mLooper->wake();
    return OK;
}

好了蒲犬,到這里我們就知道了,server端的inputChannel最終被注冊到了InputDispatcher的注冊列表中去了岸啡,所以InputDispatcher中就可以通過向server端的socket中寫入消息暖哨,然后client端就可以讀取到了。但是,這里還發(fā)現(xiàn)存在一個問題:那就是server端寫入事件消息后篇裁,怎么通知到client去開始處理呢沛慢?我們在回過頭來看一下前面介紹的InputEventReceiver的構(gòu)造函數(shù)。

client端InputChannel讀取事件并傳遞

public InputEventReceiver(InputChannel inputChannel, Looper looper) {
    // 省略若干層
    mInputChannel = inputChannel;
    mMessageQueue = looper.getQueue();
    // 將Java層的inputChannel向下層傳遞
    mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
            inputChannel, mMessageQueue);
    mCloseGuard.open("dispose");
}

在InputEventReceiver的構(gòu)造方法中調(diào)用了native方法nativeInit進(jìn)行native層的初始化

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    // 省略若干行
    sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    // 初始化Receiver
    status_t status = receiver->initialize();
    // 省略若干行
    return reinterpret_cast<jlong>(receiver.get());
}

在NativeInputEventReceiver初始化時达布,會將inputChannel的文件描述符fd添加到looper中去团甲,并且添加了looper callback為NativeInputEventReceiver實(shí)例自身,所以黍聂,當(dāng)server端寫入事件消息時躺苦,就會觸發(fā)callback,于是便調(diào)用到NativeInputEventReceiver的handleEvent方法产还。

status_t NativeInputEventReceiver::initialize() {
    // 設(shè)置文件描述符對應(yīng)的event為ALOOPER_EVENT_INPUT
    setFdEvents(ALOOPER_EVENT_INPUT);
    return OK;
}
  
void NativeInputEventReceiver::setFdEvents(int events) {
    if (mFdEvents != events) {
        mFdEvents = events;
        int fd = mInputConsumer.getChannel()->getFd();
        if (events) {
            // 將inputChannel的文件描述符添加到looper中
            // 對應(yīng)的event為ALOOPER_EVENT_INPUT
            // 并傳入了this作為loopercallback
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}

我們發(fā)現(xiàn)在handleEvent方法中匹厘,調(diào)用了consumeEvents方法來處理事件,而consumeEvents方法便是我們前面介紹過了的脐区,在其內(nèi)部會通過jni的方式將事件向Java層傳遞到InputEventReceiver的dispatchInputEvent愈诚,從而便實(shí)現(xiàn)了事件的分發(fā)。

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
    // 省略若干行
    // 接收添加的ALOOPER_EVENT_INPUT事件
    if (events & ALOOPER_EVENT_INPUT) {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        // 調(diào)用consumeEvents方法處理事件
        status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
        mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
        return status == OK || status == NO_MEMORY ? 1 : 0;
    }
    // 省略若干行
    return 1;
}

小結(jié)

通過以上分析牛隅,我們便明白了InputDispatcher是如果通過InputChannel將事件向上層進(jìn)行分發(fā)的整個過程炕柔。首先是創(chuàng)建一對InputChannel,并且會開啟一對相互連接的socket作為事件傳遞的媒介媒佣。server端的InputChannel會注冊到InputDispatcher中去以完成事件的分發(fā)匕累,并且會將其fd添加到looper中,而client端的InputChannel會在InputEventReceiver初始化時也會將其fd添加到looper中默伍,并傳入callback類接收server端寫入的事件欢嘿,這樣整個過程便串聯(lián)起來了。但是也糊,這里還存在一個問題:InputDispatcher的事件從哪里來呢际插?

InputManagerService

InputManagerService簡稱IMS,和其他系統(tǒng)服務(wù)一樣显设,是在SystemServer中創(chuàng)建并啟動框弛,它主要是用來監(jiān)測和加工輸入事件,并向上層傳遞捕捂。而且瑟枫,上文所說的InputDispatcher以及InputReader均是在InputManagerService中構(gòu)建出來的。

IMS的創(chuàng)建

在SystemServer的startOtherServices方法中指攒,直接通過new的方式創(chuàng)建出IMS實(shí)例慷妙。

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    // 省略若干行
    t.traceBegin("StartInputManagerService");
    // 創(chuàng)建IMS
    inputManager = new InputManagerService(context);
    t.traceEnd();
    // 省略若干行
}

InputManagerService的構(gòu)造方法中,會先創(chuàng)建出Handler允悦,然后通過native方法nativeInit來實(shí)現(xiàn)IMS的初始化膝擂,主要是構(gòu)建native層的IMS。

public InputManagerService(Context context) {
    this.mContext = context;
    // 創(chuàng)建出handler
    this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
    // 省略若干行
    // 調(diào)用native方法來構(gòu)建native層IMS
    mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    // 省略若干行
}

native方法中先獲取到上層傳下來的messageQueue,然后獲取對應(yīng)的Looper架馋,并構(gòu)建出NativeInputManager狞山。

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    // 獲取上層傳遞的MessageQueue
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == nullptr) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
    // 構(gòu)建NativeInputManager
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

NativeInputManager構(gòu)造中,先創(chuàng)建出native層IMS實(shí)例叉寂,然后將其添加到serviceManager中萍启。

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    // 省略若干行
    // 構(gòu)建出native層的IMS,即InputManager
    mInputManager = new InputManager(this, this);
    // 將IMS添加到serviceManager中
    defaultServiceManager()->addService(String16("inputflinger"),
            mInputManager, false);
}

在InputManager構(gòu)建時屏鳍,會分別創(chuàng)建出InputDispatcher勘纯、InputListener以及InputReader實(shí)例。這里將InputDispatcher作為InputListener傳遞到InputClassifier钓瞭,并最終傳遞到InputReader中去驳遵。

InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = createInputDispatcher(dispatcherPolicy);
    mClassifier = new InputClassifier(mDispatcher);
    mReader = createInputReader(readerPolicy, mClassifier);
}

通過以上分析,我們發(fā)現(xiàn)在IMS創(chuàng)建的最后山涡,會創(chuàng)建出InputDispatcher和InputReader堤结,InputDispatcher我們前面已經(jīng)介紹了,主要是用于分發(fā)事件佳鳖;而InputReader是用來獲取底層輸入事件的,這個我們后面會介紹到媒惕。

IMS的啟動

我們繼續(xù)來看SystemServer的startCoreServices方法系吩,在創(chuàng)建出IMS實(shí)例后,會調(diào)用其的start方法來啟動服務(wù)妒蔚。

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    // 省略若干行
    t.traceBegin("StartInputManager");
    // 將WindowCallback傳遞給IMS
    inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
    // 調(diào)用start啟動服務(wù)
    inputManager.start();
    t.traceEnd();
    // 省略若干行
}

start方法中會直接調(diào)用native的nativeStart方法來啟動native層的IMS穿挨。

public void start() {
    Slog.i(TAG, "Starting input manager");
    // 調(diào)用native方法來啟動底層IMS
    nativeStart(mPtr);
    // 省略若干行
}

nativeStart方法中會獲取到InputManager,然后調(diào)用它的start方法肴盏。

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    // 調(diào)用InputManager的start方法
    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

在InputManager的start方法中科盛,先調(diào)用了InputDispatcher的start方法來啟動InputDispatcher,然后調(diào)用InputReader的start方法啟動InputReader菜皂。

status_t InputManager::start() {
    status_t result = mDispatcher->start();
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }
  
    result = mReader->start();
    if (result) {
        ALOGE("Could not start InputReader due to error %d.", result);
  
        mDispatcher->stop();
        return result;
    }
  
    return OK;
}

小結(jié)

通過以上IMS的創(chuàng)建和啟動過程分析贞绵,我們能夠看到在IMS的創(chuàng)建和啟動都是在SystemServer的startCoreServices方法中觸發(fā)的,另外在創(chuàng)建的時候也會分別創(chuàng)建出InputDispatcher和InputReader恍飘;而且榨崩,在調(diào)用start方法啟動的時候,最終也會觸發(fā)調(diào)用InputDispatcher和InputReader的start方法來啟動各自實(shí)例章母。

InputDispatcher

通過上述分析母蛛,知道了InputDispatcher的創(chuàng)建是在IMS創(chuàng)建時創(chuàng)建,那么它是如何啟動起來的呢乳怎?我們繼續(xù)看InputDispatcher的start方法彩郊。

InputDispatcher啟動

在InputDispatcher的start方法中,會創(chuàng)建出InputThread線程,并傳入了兩個函數(shù)指針:dispatchOnce以及mLooper->wake秫逝。

status_t InputDispatcher::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    // 直接構(gòu)造出Thread恕出,傳入兩個回調(diào)函數(shù)
    mThread = std::make_unique<InputThread>(
            "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
    return OK;
}

繼續(xù)看InputThread的構(gòu)造過程,發(fā)現(xiàn)初始化列表中對傳入的回調(diào)函數(shù)進(jìn)行了保存筷登,然后構(gòu)建InputThreadImpl并調(diào)用其run方法將線程啟動起來剃根。

InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
    // 這里保存wake回調(diào)函數(shù)
      : mName(name), mThreadWake(wake) {
    // 將loop函數(shù)傳入InputThreadImpl
    mThread = new InputThreadImpl(loop);
    mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
}
  
InputThread::~InputThread() {
    mThread->requestExit();
    // 調(diào)用wake函數(shù)
    if (mThreadWake) {
        mThreadWake();
    }
    mThread->requestExitAndWait();
}
  
class InputThreadImpl : public Thread {
public:
    explicit InputThreadImpl(std::function<void()> loop)
                                            // 保存loop函數(shù)
          : Thread(/* canCallJava */ true), mThreadLoop(loop) {}
  
    ~InputThreadImpl() {}
  
private:
    std::function<void()> mThreadLoop;
  
    bool threadLoop() override {
        // 在線程的loop循環(huán)中調(diào)用了傳入的loop函數(shù)。
        mThreadLoop();
        // 返回true線程會一直運(yùn)行前方,直到requestExit被調(diào)用時退出
        return true;
    }
};

通過以上分析狈醉,我們發(fā)現(xiàn)InputThread構(gòu)造時會創(chuàng)建出線程并將其啟動起來,傳入的loop函數(shù)(dispatchOnce)最終會作為線程的loop來執(zhí)行惠险,而wake函數(shù)(mLooper->wake)也會在InputThread析構(gòu)時調(diào)用苗傅。

InputDispatcher分發(fā)事件

通過前面的介紹,我們了解到在InputDispatcher啟動時創(chuàng)建了線程班巩,并且將dispatchOnce作為線程的執(zhí)行函數(shù)傳入到InputThread中渣慕。所以,當(dāng)InputDispatcher線程被喚醒后就會執(zhí)行dispatchOnce方法來分發(fā)事件抱慌。

InputDispatcher分發(fā)事件

我們繼續(xù)逊桦,在dispatchOnce方法中,首先會判斷是否有command需要處理(如:configChanged抑进,focusChanged等)强经,如果有就會調(diào)用runCommandsLockedInterruptible方法執(zhí)行所有command,然后會再次觸發(fā)wake執(zhí)行事件的處理寺渗;如果沒有則直接調(diào)用dispatchOnceInnerLocked來處理輸入事件匿情;最后,looper會再次進(jìn)入睡眠等待下一次喚醒信殊。

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        std::scoped_lock _l(mLock);
        mDispatcherIsAlive.notify_all();
  
        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        if (!haveCommandsLocked()) {
            // 這里沒有command需要處理炬称,就開始分發(fā)事件
            dispatchOnceInnerLocked(&nextWakeupTime);
        }
  
        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        // 處理command,并修改nextWakeupTime
        if (runCommandsLockedInterruptible()) {
            nextWakeupTime = LONG_LONG_MIN;
        }
  
        // If we are still waiting for ack on some events,
        // we might have to wake up earlier to check if an app is anr'ing.
        // 檢測是否事件分發(fā)出現(xiàn)anr
        const nsecs_t nextAnrCheck = processAnrsLocked();
        nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
  
        // We are about to enter an infinitely long sleep, because we have no commands or
        // pending or queued events
        if (nextWakeupTime == LONG_LONG_MAX) {
            mDispatcherEnteredIdle.notify_all();
        }
    } // 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);
    // 處理完成后調(diào)用looper的pollOnce進(jìn)入睡眠狀態(tài)涡拘,等待下一次喚醒玲躯,
    // 如果是處理了command,則這個timeoutMillis為0
    // 所以會接著執(zhí)行一次loop
    mLooper->pollOnce(timeoutMillis);
}

dispatchOnceInnerLocked方法會先判斷是否有待分發(fā)的事件鳄乏,沒有則從事件隊(duì)列中取出一個事件府蔗;然后根據(jù)事件不同的type調(diào)用不同的dispatch方法進(jìn)行事件分發(fā)。

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    // 省略若干行
    // Ready to start a new event.
    // If we don't already have a pending event, go grab one.
    if (!mPendingEvent) {
        // 如果沒有待分發(fā)的事件
        if (mInboundQueue.empty()) {
            // 省略若干行
            // Nothing to do if there is no pending event.
            // 事件隊(duì)列為空汞窗,并且沒有待分發(fā)的事件姓赤,直接返回
            if (!mPendingEvent) {
                return;
            }
        } else {
            // Inbound queue has at least one entry.
            // 從隊(duì)列中取出一個事件
            mPendingEvent = mInboundQueue.front();
            mInboundQueue.pop_front();
            traceInboundQueueLengthLocked();
        }
        // 省略若干行
    switch (mPendingEvent->type) {
        // 省略若干行
        // 根據(jù)事件的type分別進(jìn)行處理
        case EventEntry::Type::KEY: {
            KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
            // 省略若干行
            // 分發(fā)key事件
            done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
            break;
        }
  
        case EventEntry::Type::MOTION: {
            // 省略若干行
            // 分發(fā)motion事件
            done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
            break;
        }
    }
}

這里以key事件為例繼續(xù)介紹,dispatchKeyLocked中首先通過findFocusedWindowTargetsLocked方法查找到焦點(diǎn)窗口仲吏,然后調(diào)用dispatchEventLocked朝焦點(diǎn)窗口上分發(fā)事件不铆。

bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
                                        DropReason* dropReason, nsecs_t* nextWakeupTime) {
    // 省略若干行
    // Identify targets.
    std::vector<InputTarget> inputTargets;
    // 查找focus window
    int32_t injectionResult =
            findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
    // 省略若干行
    // 將事件分發(fā)到對應(yīng)window上去
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

dispatchEventLocked方法中會遍歷所有查找到的focus窗口(inputTarget)蝌焚,然后通過inputChannel獲取到鏈接對象connection,最后通過prepareDispatchCycleLocked將事件分發(fā)出去誓斥。

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
                                          const std::vector<InputTarget>& inputTargets) {
    // 省略若干行
    // 遍歷所有的inputTarget
    for (const InputTarget& inputTarget : inputTargets) {
        // 通過inputChannel獲取connection
        sp<Connection> connection =
                getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
        if (connection != nullptr) {
            // 開始事件分發(fā)
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
        }
        // 省略若干行
    }
}

prepareDispatchCycleLocked方法中先判斷是否需要split motion事件并進(jìn)行處理只洒,最后調(diào)用enqueueDispatchEntriesLocked方法將待分發(fā)的事件添加到mOutboundQueue隊(duì)列中。

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
                                                 const sp<Connection>& connection,
                                                 EventEntry* eventEntry,
                                                 const InputTarget& inputTarget) {
    // 省略若干行
    // Split a motion event if needed.
    // 如果需要split motion事件則進(jìn)行處理
    if (inputTarget.flags & InputTarget::FLAG_SPLIT) {
        LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION,
                            "Entry type %s should not have FLAG_SPLIT",
                            EventEntry::typeToString(eventEntry->type));
  
        const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
        if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
            // 省略若干行
            enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget);
            splitMotionEntry->release();
            return;
        }
    }
  
    // Not splitting.  Enqueue dispatch entries for the event as is.
    // 將將要分發(fā)的事件入隊(duì)
    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}

enqueueDispatchEntriesLocked方法中會分別處理不同的flag對應(yīng)的事件將其添加到outboundQueue中劳坑,最后通過調(diào)用startDispatchCycleLocked開始事件的分發(fā)毕谴。

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
                                                   const sp<Connection>& connection,
                                                   EventEntry* eventEntry,
                                                   const InputTarget& inputTarget) {
    // 省略若干行
  
    bool wasEmpty = connection->outboundQueue.empty();
    // 分別處理不同flag對應(yīng)的event,并將其添加到outboundQueue隊(duì)列中
    // 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.empty()) {
        // 如果有event被添加到隊(duì)列則開始處理
        startDispatchCycleLocked(currentTime, connection);
    }
}

startDispatchCycleLocked方法中通過遍歷outboundQueue隊(duì)列距芬,取出所有的event涝开,然后根據(jù)其type分別調(diào)用InputPublisher的publishXxxEvent將事件分發(fā)出去。

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
                                               const sp<Connection>& connection) {
    // 省略若干行
    // 循環(huán)遍歷outboundQueue隊(duì)列
    while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
        // 從outboundQueue隊(duì)列取出事件
        DispatchEntry* dispatchEntry = connection->outboundQueue.front();
        dispatchEntry->deliveryTime = currentTime;
        const nsecs_t timeout =
                getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
        dispatchEntry->timeoutTime = currentTime + timeout;
  
        // Publish the event.
        status_t status;
        EventEntry* eventEntry = dispatchEntry->eventEntry;
        // 根據(jù)event的不同type分別進(jìn)行分發(fā)
        switch (eventEntry->type) {
            case EventEntry::Type::KEY: {
                const KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
                std::array<uint8_t, 32> hmac = getSignature(*keyEntry, *dispatchEntry);
  
                // Publish the key event.
                // 分發(fā)key事件
                status =
                        connection->inputPublisher
                                .publishKeyEvent(dispatchEntry->seq, dispatchEntry->resolvedEventId,
                                                 keyEntry->deviceId, keyEntry->source,
                                                 keyEntry->displayId, std::move(hmac),
                                                 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;
                // 省略若干行
                // 分發(fā)motion事件
                // Publish the motion event.
                status = connection->inputPublisher
                                 .publishMotionEvent(dispatchEntry->seq,
                                                     dispatchEntry->resolvedEventId,
                                                     motionEntry->deviceId, motionEntry->source,
                                                     motionEntry->displayId, std::move(hmac),
                                                     dispatchEntry->resolvedAction,
                                                     motionEntry->actionButton,
                                                     dispatchEntry->resolvedFlags,
                                                     motionEntry->edgeFlags, motionEntry->metaState,
                                                     motionEntry->buttonState,
                                                     motionEntry->classification, xScale, yScale,
                                                     xOffset, yOffset, motionEntry->xPrecision,
                                                     motionEntry->yPrecision,
                                                     motionEntry->xCursorPosition,
                                                     motionEntry->yCursorPosition,
                                                     motionEntry->downTime, motionEntry->eventTime,
                                                     motionEntry->pointerCount,
                                                     motionEntry->pointerProperties, usingCoords);
                reportTouchEventForStatistics(*motionEntry);
                break;
            }
        // 省略若干行
    }
}

這里以key事件為例繼續(xù)介紹,在publishKeyEvent方法中,首先會根據(jù)傳入的event詳細(xì)信息構(gòu)建出InputMessage矫户,然后再調(diào)用InputChannel的sendMessage方法將msg發(fā)送出去。

status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t eventId, int32_t deviceId,
                                         int32_t source, int32_t displayId,
                                         std::array<uint8_t, 32> hmac, int32_t action,
                                         int32_t flags, int32_t keyCode, int32_t scanCode,
                                         int32_t metaState, int32_t repeatCount, nsecs_t downTime,
                                         nsecs_t eventTime) {
    // 省略若干行
    // 根據(jù)event信息構(gòu)建InputMessage
    InputMessage msg;
    msg.header.type = InputMessage::Type::KEY;
    msg.body.key.seq = seq;
    msg.body.key.eventId = eventId;
    msg.body.key.deviceId = deviceId;
    msg.body.key.source = source;
    msg.body.key.displayId = displayId;
    msg.body.key.hmac = std::move(hmac);
    msg.body.key.action = action;
    msg.body.key.flags = flags;
    msg.body.key.keyCode = keyCode;
    msg.body.key.scanCode = scanCode;
    msg.body.key.metaState = metaState;
    msg.body.key.repeatCount = repeatCount;
    msg.body.key.downTime = downTime;
    msg.body.key.eventTime = eventTime;
    // 通過InputChannel的sendMessage方法將event發(fā)送出去
    return mChannel->sendMessage(&msg);
}

sendMessage主要就是先copy一份事件msg银舱,然后調(diào)用send將msg循環(huán)寫入socket,從而實(shí)現(xiàn)輸入事件的分發(fā)跛梗。

status_t InputChannel::sendMessage(const InputMessage* msg) {
    const size_t msgLength = msg->size();
    InputMessage cleanMsg;
    // copy一份msg
    msg->getSanitizedCopy(&cleanMsg);
    ssize_t nWrite;
    do {
        // 通過socket循環(huán)寫入msg
        nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);
    // 省略若干行
    return OK;
}

InputReader(InputDispatcher事件的來源)

InputDispatcher中的事件是從InputReader中來的寻馏,InputReader從EventHub中獲取到輸入事件后,會通過調(diào)用InputDispatcher的notifyXxx方法來將事件傳遞到InuptDispatcher中核偿。

InputReader啟動

在IMS的start方法中會調(diào)用InputReader的start方法來啟動InputReader诚欠,我們繼續(xù)看InputReader的start方法。在start方法中宪祥,會創(chuàng)建出InputThread線程聂薪,這里注意家乘,創(chuàng)建線程時傳入了兩個函數(shù)指針(laumda表達(dá)式):loopOnce和mEventHub->wake蝗羊。通過上面對InputThread的介紹,我們知道最終仁锯,loopOnce會作為線程的循環(huán)方法進(jìn)行調(diào)用耀找,而mEventHub->wake最終也會在線程析構(gòu)時觸發(fā)。

status_t InputReader::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    // 直接構(gòu)造出Thread业崖,傳入兩個回調(diào)函數(shù)
    mThread = std::make_unique<InputThread>(
            "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
    return OK;
}

InputReader處理事件

InputReader在其線程的threadLoop中會調(diào)用loopOnce從EventHub中獲取輸入事件野芒,如果獲取到事件,則繼續(xù)調(diào)用processEventsLocked進(jìn)行處理双炕。接著會調(diào)用到InputDevice -> InputMapper -> InputDispatcher(InputListenerInterface)狞悲,在InputDispatcher中觸發(fā)notifyXxx方法,從而將事件分發(fā)出去妇斤。

InputReader處理事件
void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    std::vector<InputDeviceInfo> inputDevices;
    // 省略若干行
    // 從EventHub中獲取事件
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
  
    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();
        // 獲取到輸入事件則調(diào)用processEventsLocked進(jìn)行處理
        if (count) {
            processEventsLocked(mEventBuffer, count);
        }
    // 省略若干行
}

processEventsLocked方法中會根據(jù)事件的type摇锋,分別處理device的變更事件以及輸入事件丹拯。輸入事件則繼續(xù)調(diào)用processEventsForDeviceLocked來處理,device改變則同步改變mDevices荸恕。

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) {
            // 省略若干行
            // 這里事件類型如果不是device change事件則繼續(xù)處理
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            // device change事件
            switch (rawEvent->type) {
                case EventHubInterface::DEVICE_ADDED:
                    // device接入乖酬,將device添加到全局map中(mDevices)
                    addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                case EventHubInterface::DEVICE_REMOVED: // device斷開
                    removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                case EventHubInterface::FINISHED_DEVICE_SCAN: // device scan
                    handleConfigurationChangedLocked(rawEvent->when);
                    break;
                default:
                    ALOG_ASSERT(false); // can't happen
                    break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

processEventsForDeviceLocked中從device的map中根據(jù)eventHubId查找device,如果找到則調(diào)用對應(yīng)device的process方法繼續(xù)處理融求。

void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
                                               size_t count) {
    // 通過eventHubId從map中查找InputDevice
    auto deviceIt = mDevices.find(eventHubId);
    if (deviceIt == mDevices.end()) {
        // 沒有對應(yīng)的device則直接返回
        ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
        return;
    }
  
    std::shared_ptr<InputDevice>& device = deviceIt->second;
    // device被忽略則返回
    if (device->isIgnored()) {
        // ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }
    // 調(diào)用InputDevice的process繼續(xù)處理事件
    device->process(rawEvents, count);
}

InputDevice的process中會遍歷所有的event咬像,并且根據(jù)event中的deviceId從mDevices中找到對應(yīng)的device,然后遍歷其所有的InputMapper生宛,并調(diào)用mapper的process進(jìn)行事件處理县昂。

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    // Process all of the events in order for each mapper.
    // We cannot simply ask each mapper to process them in bulk because mappers may
    // have side-effects that must be interleaved.  For example, joystick movement events and
    // gamepad button presses are handled by different mappers but they should be dispatched
    // in the order received.
    for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
        // 省略若干行
        // 從devices中找到對應(yīng)的device,然后遍歷其所有inputMapper茅糜,并調(diào)用其process方法進(jìn)行處理
        for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
            mapper.process(rawEvent);
        });
        --count;
    }
}
  
inline void for_each_mapper_in_subdevice(int32_t eventHubDevice,
                                            std::function<void(InputMapper&)> f) {
    auto deviceIt = mDevices.find(eventHubDevice);
    // 查找對應(yīng)的device
    if (deviceIt != mDevices.end()) {
        auto& devicePair = deviceIt->second;
        auto& mappers = devicePair.second;
        // 遍歷該device的所有InputMapper七芭,并調(diào)用函數(shù)指針f
        for (auto& mapperPtr : mappers) {
            f(*mapperPtr);
        }
    }
}

InputMapper在InputReader中處理device接入事件觸發(fā)時會調(diào)用addDeviceLocked方法,然后會調(diào)用到createDeviceLocked方法來創(chuàng)建出對應(yīng)的InputDevice蔑赘,創(chuàng)建出device后狸驳,便調(diào)用它的addEventHubDevice來創(chuàng)建出相應(yīng)的InputMapper并添加到全局map中。

void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
    // 根據(jù)eventHubId查找device
    if (mDevices.find(eventHubId) != mDevices.end()) {
        ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);
        return;
    }
  
    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
    // 創(chuàng)建device
    std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);
    // 省略若干行
}
  
std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
        int32_t eventHubId, const InputDeviceIdentifier& identifier) {
    // 省略若干行
    std::shared_ptr<InputDevice> device;
    if (deviceIt != mDevices.end()) {
        // 如果device已經(jīng)存在則直接返回
        device = deviceIt->second;
    } else {
        // 否則創(chuàng)建出對應(yīng)的InputDevice
        int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();
        device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
                                               identifier);
    }
    // 調(diào)用addEventHubDevice缩赛,構(gòu)建出相應(yīng)的mapper
    device->addEventHubDevice(eventHubId);
    return device;
}

通過addEventHubDevice方法耙箍,可以看出針對不同的device類型,會構(gòu)建出不同的mapper酥馍,最后將mapper數(shù)組添加到了mDevices的全局map中辩昆。后面我們以KeyboardInputMapper為例介紹key事件的傳遞過程。

void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
    if (mDevices.find(eventHubId) != mDevices.end()) {
        return;
    }
    std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
    uint32_t classes = contextPtr->getDeviceClasses();
    std::vector<std::unique_ptr<InputMapper>> mappers;
  
    // Check if we should skip population
    if (!populateMappers) {
        mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
        return;
    }
  
    // Switch-like devices.
    if (classes & INPUT_DEVICE_CLASS_SWITCH) {
        mappers.push_back(std::make_unique<SwitchInputMapper>(*contextPtr));
    }
  
    // Scroll wheel-like devices.
    if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
        mappers.push_back(std::make_unique<RotaryEncoderInputMapper>(*contextPtr));
    }
  
    // Vibrator-like devices.
    if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
        mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));
    }
  
    // Keyboard-like devices.
    uint32_t keyboardSource = 0;
    int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
    if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
        keyboardSource |= AINPUT_SOURCE_KEYBOARD;
    }
    if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
        keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
    }
    if (classes & INPUT_DEVICE_CLASS_DPAD) {
        keyboardSource |= AINPUT_SOURCE_DPAD;
    }
    if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
        keyboardSource |= AINPUT_SOURCE_GAMEPAD;
    }
  
    if (keyboardSource != 0) {
        mappers.push_back(
                std::make_unique<KeyboardInputMapper>(*contextPtr, keyboardSource, keyboardType));
    }
  
    // Cursor-like devices.
    if (classes & INPUT_DEVICE_CLASS_CURSOR) {
        mappers.push_back(std::make_unique<CursorInputMapper>(*contextPtr));
    }
  
    // Touchscreens and touchpad devices.
    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
        mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr));
    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
        mappers.push_back(std::make_unique<SingleTouchInputMapper>(*contextPtr));
    }
  
    // Joystick-like devices.
    if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
        mappers.push_back(std::make_unique<JoystickInputMapper>(*contextPtr));
    }
  
    // External stylus-like devices.
    if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
        mappers.push_back(std::make_unique<ExternalStylusInputMapper>(*contextPtr));
    }
  
    // insert the context into the devices set
    mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
}

回到InputDevice的process方法中旨袒,循環(huán)遍歷了所有的mapper并調(diào)用其process方法汁针,這里以KeyboardInputMapper來介紹key事件的處理過程。

void KeyboardInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
        // 如果是key事件
        case EV_KEY: {
            int32_t scanCode = rawEvent->code;
            int32_t usageCode = mCurrentHidUsage;
            mCurrentHidUsage = 0;
            // 如果code為keyboard或者游戲面板對應(yīng)的key
            if (isKeyboardOrGamepadKey(scanCode)) {
                processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
            }
            break;
        }
        // 省略若干行
    }
}

processKey方法中砚尽,會根據(jù)event是否為down以及event的其他屬性構(gòu)建出NotifyKeyArgs施无,然后通過getListener方法獲取到InputListener,并通過其notifyKey方法將事件傳遞到InputDispatcher中必孤。

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) {
    int32_t keyCode;
    int32_t keyMetaState;
    uint32_t policyFlags;
    // 省略若干行
    // 根據(jù)event內(nèi)容構(gòu)建相應(yīng)的args
    NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(),
                       policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
                       AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
    // 獲取InputListener猾骡,并調(diào)用其notifyKey方法傳遞key事件
    getListener()->notifyKey(&args);
}

notifyKey方法中首先會構(gòu)建出KeyEvent事件對象,并通過IMS傳遞到Java層的interceptKeyBeforeQueueing方法敷搪;然后根據(jù)args構(gòu)建KeyEnvtry兴想,并將其添加到mInboundQueue隊(duì)列中;最后調(diào)用wake方法喚醒looper赡勘。

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
    // 省略若干行
    // 根據(jù)args構(gòu)建KeyEvent
    KeyEvent event;
    event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
                     args->action, flags, keyCode, args->scanCode, metaState, repeatCount,
                     args->downTime, args->eventTime);
  
    android::base::Timer t;
    // 調(diào)用IMS的interceptKeyBeforeQueueing
    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
    // 省略若干行
    // 構(gòu)建KeyEntry
    KeyEntry* newEntry =
            new KeyEntry(args->id, args->eventTime, args->deviceId, args->source,
                            args->displayId, policyFlags, args->action, flags, keyCode,
                            args->scanCode, metaState, repeatCount, args->downTime);
    // 將KeyEntry添加到mInboundQueue里面
    needWake = enqueueInboundEventLocked(newEntry);
    // 省略若干行
    // 如果需要wake則喚醒looper
    if (needWake) {
        mLooper->wake();
    }
}

enqueueInboundEventLocked方法中會將EventEntry添加到mInboundQueue隊(duì)列中嫂便,然后如果需要wake就喚醒looper,然后就會觸發(fā)threadLoop闸与,從而調(diào)用dispatchOnce方法回到InputDispatcher中分發(fā)事件毙替。

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    bool needWake = mInboundQueue.empty();
    // 將EventEntry添加到mInboundQueue隊(duì)列中
    mInboundQueue.push_back(entry);
    traceInboundQueueLengthLocked();
    // 省略若干行
    return needWake;
}

EventHub

通過前面InputReader的介紹曼振,我們發(fā)現(xiàn)輸入事件的源頭是通過調(diào)用EventHub的getEvents方法獲取的。那么蔚龙,EventHub是如何創(chuàng)建以及進(jìn)行事件的獲取的呢冰评?

EventHub獲取事件

EventHub的創(chuàng)建

我們回到InputReader的構(gòu)造方法,發(fā)現(xiàn)在InputReader構(gòu)造方法的初始化列表中木羹,會賦值全局變量mEventHub甲雅。

InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
                         const sp<InputReaderPolicyInterface>& policy,
                         const sp<InputListenerInterface>& listener)
      : mContext(this),
      // 初始化mEventHub
        mEventHub(eventHub),
        mPolicy(policy),
        mGlobalMetaState(0),
        mGeneration(1),
        mNextInputDeviceId(END_RESERVED_ID),
        mDisableVirtualKeysTimeout(LLONG_MIN),
        mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {
    mQueuedListener = new QueuedInputListener(listener);
    { // acquire lock
        AutoMutex _l(mLock);
  
        refreshConfigurationLocked(0);
        updateGlobalMetaStateLocked();
    } // release lock
}

在初始化列表中對全局變量mEventHub進(jìn)行了初始化,通過前面介紹我們知道坑填,InputReader是在InputManager中構(gòu)建出來的抛人,那么我們繼續(xù)看。

InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = createInputDispatcher(dispatcherPolicy);
    mClassifier = new InputClassifier(mDispatcher);
    // 通過createInputReader創(chuàng)建出InputReader
    mReader = createInputReader(readerPolicy, mClassifier);
}
  
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,
                                           const sp<InputListenerInterface>& listener) {
                          // 這里直接通過std::make_unique構(gòu)建出EventHub實(shí)例
    return new InputReader(std::make_unique<EventHub>(), policy, listener);
}

在InputManager中通過createInputReader構(gòu)建出InputReader實(shí)例脐瑰,而在createInputReader方法中妖枚,會首先通過std::make_unique構(gòu)建出EventHub實(shí)例,繼續(xù)看EventHub的構(gòu)造函數(shù)苍在。

EventHub::EventHub(void)
      : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
        mNextDeviceId(1),
        mControllerNumbers(),
        mOpeningDevices(nullptr),
        mClosingDevices(nullptr),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false),
        mNeedToScanDevices(true),
        mPendingEventCount(0),
        mPendingEventIndex(0),
        mPendingINotify(false) {
    ensureProcessCanBlockSuspend();
    // 創(chuàng)建出epoll
    mEpollFd = epoll_create1(EPOLL_CLOEXEC);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
    // 創(chuàng)建inotify
    mINotifyFd = inotify_init();
    // 通過inotify來監(jiān)聽DEVICE_PATH路徑(/dev/input)下的文件改變(增加或者刪除)
    mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
    // 省略若干行
    struct epoll_event eventItem = {};
    eventItem.events = EPOLLIN | EPOLLWAKEUP;
    eventItem.data.fd = mINotifyFd;
    // 將mINotifyFd添加到epoll中
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);
    // 創(chuàng)建管道
    int wakeFds[2];
    result = pipe(wakeFds);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
  
    mWakeReadPipeFd = wakeFds[0];
    mWakeWritePipeFd = wakeFds[1];
    // 設(shè)置管道讀取端非阻塞屬性
    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
                        errno);
    // 設(shè)置管道寫入端非阻塞屬性
    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
                        errno);
  
    eventItem.data.fd = mWakeReadPipeFd;
    // 將讀取端管道描述符添加到epoll
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
                        errno);
}

在EventHub的構(gòu)造方法中绝页,我們可以看到:首先會創(chuàng)建出epoll,然后創(chuàng)建出inotify來監(jiān)聽/dev/input路徑下文件的增刪寂恬,并將inotify添加到epoll中進(jìn)行監(jiān)聽续誉,還會創(chuàng)建出一個管道,并將管道讀取端也添加到epoll中初肉。這樣當(dāng)有新的輸入設(shè)備接入或者刪除事酷鸦,就會觸發(fā)喚醒epoll進(jìn)行處理。

EventHub如何獲取輸入事件

在上面介紹的InputReader中牙咏,我們了解到loopOnce方法中通過調(diào)用EventHub的getEvents來獲取輸入事件臼隔。那么,我們繼續(xù)看getEvents方法妄壶,此方法比較長摔握,我們先看下大概的框架。

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    for (;;) {
        // Reopen input devices if needed.
        if (mNeedToReopenDevices) {
            // 如果存在需要reopen的設(shè)備盯拱,則先關(guān)閉所有device
            // 然后設(shè)置需要scan設(shè)備的標(biāo)識
        }
  
        // Report any devices that had last been added/removed.
        while (mClosingDevices) {
            // 如果存在需要關(guān)閉的設(shè)備盒发,則遍歷所有需要關(guān)閉的設(shè)備鏈表例嘱,
            // 刪除對應(yīng)的device狡逢,并構(gòu)建event
        }
        // 需要掃描device,則調(diào)用scanDevicesLocked方法掃描
        // 最后更新device列表
        if (mNeedToScanDevices) {
        }
        //存在需要open的device拼卵,則更新mOpeningDevices鏈表
        // 并構(gòu)建event
        while (mOpeningDevices != nullptr) {
        }
        // 需要scanFinish事件奢浑,則構(gòu)建對應(yīng)event
        if (mNeedToSendFinishedDeviceScan) {
        }
  
        // Grab the next input event.
        // 遍歷需要處理的事件列表
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            if (eventItem.data.fd == mINotifyFd) {
                // 如果是inotify事件,則修改對應(yīng)標(biāo)識腋腮,后面會掃描處理對于的變更
            }
  
            if (eventItem.data.fd == mWakeReadPipeFd) {
                // 管道事件雀彼,則設(shè)置wake為true壤蚜,跳出循環(huán)繼續(xù)執(zhí)行
            }
            // This must be an input event
            if (eventItem.events & EPOLLIN) {
                // 真正的輸入事件
            }
        }
        // 開始wait時釋放鎖
        mLock.unlock(); // release lock before poll
        // epoll等待喚醒
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
        // 喚醒開始執(zhí)行時則加鎖
        mLock.lock(); // reacquire lock after poll
    }
  
    // All done, return the number of events we read.
    return event - buffer;
}

通過以上getEvents方法的大致流程,能夠看到首先會查看是否有需要reopen的device并進(jìn)行處理徊哑,接著處理需要close的device袜刷,然后是判斷是否需要掃描設(shè)備并進(jìn)行device掃描;接著處理新接入的設(shè)備莺丑,然后開始遍歷待處理的事件著蟹,并分別處理inotify、管道以及真正的輸入事件梢莽;過程中如果有event被處理則就會break掉for循環(huán)繼續(xù)進(jìn)行下一次處理萧豆,如果所有事件都已處理完就會走到下面的epoll_wait進(jìn)入wait狀態(tài)等待喚醒。

EventHub處理reopen設(shè)備
// Reopen input devices if needed.
if (mNeedToReopenDevices) {
    // 設(shè)置mNeedToReopenDevices為false昏名,避免下次循環(huán)繼續(xù)處理
    mNeedToReopenDevices = false;
  
    ALOGI("Reopening all input devices due to a configuration change.");
    // 關(guān)閉所有device
    closeAllDevicesLocked();
    // 標(biāo)識需要掃描device涮雷,后面循環(huán)會進(jìn)行掃描設(shè)備
    mNeedToScanDevices = true;
    // 跳出for循環(huán),繼續(xù)后續(xù)處理
    break; // return to the caller before we actually rescan
}

處理reopen設(shè)備轻局,首先是重置reopen標(biāo)識洪鸭,然后調(diào)用closeAllDevicesLocked來關(guān)閉所有的device,接著標(biāo)識設(shè)備需要掃描仑扑,最后break退出此次循環(huán)卿嘲,繼續(xù)下一次循環(huán)處理。繼續(xù)看closeAllDevicesLocked方法:

void EventHub::closeAllDevicesLocked() {
    mUnattachedVideoDevices.clear();
    while (mDevices.size() > 0) {
        // 循環(huán)遍歷所有device夫壁,并調(diào)用closeDeviceLocked來進(jìn)行關(guān)閉
        closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1));
    }
}
  
void EventHub::closeDeviceLocked(Device* device) {
    // 省略若干行
    // 從epoll移除此device的監(jiān)聽
    unregisterDeviceFromEpollLocked(device);
    // 省略若干行
    // 從device列表中移除此設(shè)備
    mDevices.removeItem(device->id);
    // 關(guān)閉device
    device->close();
  
    // Unlink for opening devices list if it is present.
    Device* pred = nullptr;
    bool found = false;
    // 從已經(jīng)打開的device列表中查找對應(yīng)的device
    for (Device* entry = mOpeningDevices; entry != nullptr;) {
        if (entry == device) {
            found = true;
            break;
        }
        pred = entry;
        entry = entry->next;
    }
    // 如果找到拾枣,則從打開的device列表中將其移除
    if (found) {
        // Unlink the device from the opening devices list then delete it.
        // We don't need to tell the client that the device was closed because
        // it does not even know it was opened in the first place.
        ALOGI("Device %s was immediately closed after opening.", device->path.c_str());
        if (pred) {
            pred->next = device->next;
        } else {
            mOpeningDevices = device->next;
        }
        // 刪除對應(yīng)device
        delete device;
    } else {
        // Link into closing devices list.
        // The device will be deleted later after we have informed the client.
        // 打開的device列表中沒找到,則將device添加到待移除的設(shè)備列表中
        device->next = mClosingDevices;
        mClosingDevices = device;
    }
}
EventHub處理close設(shè)備

關(guān)閉device時首先從epoll中刪除對應(yīng)的監(jiān)聽并從device列表中將其移除盒让,然后在已經(jīng)打開的device列表中查找梅肤,如果找到則將其從open的device列表中移除,否則就將其添加到close的device列表中去邑茄,后面會處理close列表姨蝴。這里我們繼續(xù)看下epoll移除device的unregisterDeviceFromEpollLocked方法:

status_t EventHub::unregisterDeviceFromEpollLocked(Device* device) {
    if (device->hasValidFd()) {
        // 如果設(shè)備存在有效的fd,則調(diào)用unregisterFdFromEpoll將其從epoll中移除
        status_t result = unregisterFdFromEpoll(device->fd);
    }
    return OK;
}
  
status_t EventHub::unregisterFdFromEpoll(int fd) {
    // 調(diào)用epoll_ctl并傳遞EPOLL_CTL_DEL的flag將fd從epoll中移除
    if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, nullptr)) {
        ALOGW("Could not remove fd from epoll instance: %s", strerror(errno));
        return -errno;
    }
    return OK;
}

接著我們繼續(xù)看getEvents中對帶關(guān)閉設(shè)備的處理過程:

// Report any devices that had last been added/removed.
// 遍歷所有需要關(guān)閉的device鏈表
while (mClosingDevices) {
    Device* device = mClosingDevices;
    ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
    // 移動表頭到到下一個位置
    mClosingDevices = device->next;
    // 構(gòu)建設(shè)備移除的event
    event->when = now;
    event->deviceId = (device->id == mBuiltInKeyboardId)
            ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
            : device->id;
    event->type = DEVICE_REMOVED;
    event += 1;
    // 刪除對于device
    delete device;
    // 標(biāo)識需要構(gòu)建掃描完成的條件
    mNeedToSendFinishedDeviceScan = true;
}

處理關(guān)閉的device肺缕,首先是遍歷整個需要關(guān)閉的device鏈表左医,并依次對每一個device,構(gòu)造設(shè)備移除的event同木,然后刪除對應(yīng)的device浮梢,最后標(biāo)識需要構(gòu)建掃描完成的事件條件,待后面添加掃描完成的event彤路。

EventHub掃描設(shè)備

前面如果有處理reopen設(shè)備秕硝,則會關(guān)閉所有設(shè)備,并設(shè)置需要掃描設(shè)備的標(biāo)識洲尊,然后這里會調(diào)用scanDevicesLocked方法來掃描device远豺。

if (mNeedToScanDevices) {
    // 重置需要掃描的標(biāo)識奈偏,避免下一次繼續(xù)掃描設(shè)備
    mNeedToScanDevices = false;
    // 開始掃描設(shè)備
    scanDevicesLocked();
    // 標(biāo)識后面需要有掃描完成的event
    mNeedToSendFinishedDeviceScan = true;
}

掃描設(shè)備會調(diào)用scanDevicesLocked方法進(jìn)行掃描處理,我們繼續(xù)看:

void EventHub::scanDevicesLocked() {
    // 繼續(xù)調(diào)用scanDirLocked來掃描設(shè)備躯护,這里傳入的路徑為/dev/input
    status_t result = scanDirLocked(DEVICE_PATH);
    if (result < 0) {
        ALOGE("scan dir failed for %s", DEVICE_PATH);
    }
    // 省略若干行
    // 如果存在虛擬的鍵盤惊来,則在這里創(chuàng)建虛擬鍵盤
    if (mDevices.indexOfKey(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) < 0) {
        createVirtualKeyboardLocked();
    }
}

首先調(diào)用scanDirLocked掃描/dev/input目錄來索引可用的device,然后判斷如果存在虛擬的鍵盤棺滞,則調(diào)用createVirtualKeyboardLocked方法來創(chuàng)建虛擬鍵盤設(shè)備唁盏。

status_t EventHub::scanDirLocked(const char* dirname) {
    char devname[PATH_MAX];
    char* filename;
    DIR* dir;
    struct dirent* de;
    // 打開/dev/input目錄
    dir = opendir(dirname);
    if (dir == nullptr) return -1;
    strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/';
    // 遍歷/dev/input目錄
    while ((de = readdir(dir))) {
        if (de->d_name[0] == '.' &&
            (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0')))
            continue;
        strcpy(filename, de->d_name);
        // 如果文件名有效,則打開對于device
        openDeviceLocked(devname);
    }
    // 關(guān)閉目錄
    closedir(dir);
    return 0;
}

掃描device主要是掃描/dev/input目錄检眯,遍歷每一個設(shè)備文件并調(diào)用openDeviceLocked方法來打開對應(yīng)的device厘擂,最后關(guān)閉目錄。

status_t EventHub::openDeviceLocked(const char* devicePath) {
    char buffer[80];
  
    ALOGV("Opening device: %s", devicePath);
    // 打開device文件
    int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
    // 省略若干行
    // 然后依次獲取設(shè)備的名稱锰瘸、驅(qū)動版本刽严、設(shè)備的廠商等信息、物理路徑避凝、唯一的id等信息
    // 接著判斷是鍵盤或者游戲面板舞萄、鼠標(biāo)等設(shè)備類型進(jìn)行特殊處理
    // 最后將設(shè)備添加到epoll中進(jìn)行監(jiān)聽
    if (registerDeviceForEpollLocked(device) != OK) {
        // 添加失敗則刪除設(shè)備并退出
        delete device;
        return -1;
    }
    // 省略若干行
    // 將設(shè)備添加到device列表
    addDeviceLocked(device);
    return OK;
}

openDeviceLocked方法中,首先通過open方法打開對應(yīng)的設(shè)備文件管削,然后會獲取設(shè)備的各種信息并進(jìn)行相應(yīng)的處理倒脓,接著通過registerDeviceForEpollLocked方法將device添加到epoll中去,最后再通過addDeviceLocked方法將device添加到設(shè)備列表當(dāng)中去含思。

status_t EventHub::registerDeviceForEpollLocked(Device* device) {
    // 省略若干行
    // 調(diào)用registerFdForEpoll將設(shè)備描述符添加到epoll中去
    status_t result = registerFdForEpoll(device->fd);
    // 省略若干行
    return result;
}
  
status_t EventHub::registerFdForEpoll(int fd) {
    // TODO(b/121395353) - consider adding EPOLLRDHUP
    struct epoll_event eventItem = {};
    // 設(shè)置event類型為EPOLLIN 和 EPOLLWAKEUP
    eventItem.events = EPOLLIN | EPOLLWAKEUP;
    eventItem.data.fd = fd;
    // 通過epoll_ctl調(diào)用并傳入EPOLL_CTL_ADD的flag添加對應(yīng)fd到epoll中
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
        ALOGE("Could not add fd to epoll instance: %s", strerror(errno));
        return -errno;
    }
    return OK;
}
  
void EventHub::addDeviceLocked(Device* device) {
    // 將設(shè)備添加到device列表中
    mDevices.add(device->id, device);
    // 將device添加到open的設(shè)備鏈表中
    device->next = mOpeningDevices;
    mOpeningDevices = device;
}

我們能夠看到在registerFdForEpoll方法中崎弃,設(shè)備的fd被添加為EPOLLIN和EPOLLWAKEUP類型的,所以這兩種類型的事件到來時就可以喚醒epoll工作含潘,然后在addDeviceLocked方法中會將設(shè)備添加到device列表和open的device鏈表中去饲做。

EventHub處理open設(shè)備

在getEvents方法中,會遍歷整個open的設(shè)備鏈表遏弱,迭代每個設(shè)備盆均,然后構(gòu)建設(shè)備添加的event,最后標(biāo)識掃描完成的變量漱逸;如果在處理過程中泪姨,buffer已經(jīng)滿了,則會break掉饰抒,未處理的設(shè)備會在下一次迭代時繼續(xù)處理肮砾。

// 迭代每一個open的device
 while (mOpeningDevices != nullptr) {
    Device* device = mOpeningDevices;
    ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
    // 修改頭指針
    mOpeningDevices = device->next;
    // 構(gòu)建DEVICE_ADDED的event
    event->when = now;
    event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
    event->type = DEVICE_ADDED;
    event += 1;
    // 設(shè)置scan完成標(biāo)識
    mNeedToSendFinishedDeviceScan = true;
    // buffer滿了,則跳出
    if (--capacity == 0) {
        break;
    }
}
EventHub處理event
// 迭代處理所有event
while (mPendingEventIndex < mPendingEventCount) {
    const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
    if (eventItem.data.fd == mINotifyFd) {
        // event為device變更循集,則標(biāo)識mPendingINotify唇敞,后面會進(jìn)行處理
        if (eventItem.events & EPOLLIN) {
            mPendingINotify = true;
        } else {
            ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
        }
        continue;
    }
    // event是wake管道消息
    if (eventItem.data.fd == mWakeReadPipeFd) {
        if (eventItem.events & EPOLLIN) {
            ALOGV("awoken after wake()");
            // 標(biāo)識被喚醒蔗草,后面epoll就不會進(jìn)入wait狀態(tài)
            awoken = true;
            char buffer[16];
            ssize_t nRead;
            do {// 從管道中讀取出消息內(nèi)容
                nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
            } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
        } else {
            ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
                    eventItem.events);
        }
        continue;
    }
    // 通過event中的設(shè)備描述符獲取對應(yīng)device
    Device* device = getDeviceByFdLocked(eventItem.data.fd);
    // 省略若干行
    // This must be an input event
    if (eventItem.events & EPOLLIN) {
        // event是input事件
        // 從device中讀取出事件內(nèi)容
        int32_t readSize =
                read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
        if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
            // Device was removed before INotify noticed.
            ALOGW("could not get event, removed? (fd: %d size: %" PRId32
                    " bufferSize: %zu capacity: %zu errno: %d)\n",
                    device->fd, readSize, bufferSize, capacity, errno);
            // 出錯咒彤,則關(guān)閉對應(yīng)device疆柔,并標(biāo)識設(shè)備發(fā)生變更
            deviceChanged = true;
            closeDeviceLocked(device);
        }
        // 省略若干行
        else {
            // 獲取deviceId
            int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            // 遍歷讀取到的所有event,并構(gòu)建出RawEvent
            size_t count = size_t(readSize) / sizeof(struct input_event);
            for (size_t i = 0; i < count; i++) {
                struct input_event& iev = readBuffer[i];
                event->when = processEventTimestamp(iev);
                event->deviceId = deviceId;
                event->type = iev.type;
                event->code = iev.code;
                event->value = iev.value;
                event += 1;
                capacity -= 1;
            }
            // 如果buffer滿了镶柱,則break掉
            if (capacity == 0) {
                // The result buffer is full.  Reset the pending event index
                // so we will try to read the device again on the next iteration.
                mPendingEventIndex -= 1;
                break;
            }
        }
    }
}

這里處理event時旷档,首先處理設(shè)備的變更事件,然后會處理wake管道事件歇拆,最后才會處理真正的input事件鞋屈;處理input事件時會遍歷每一個獲取到的event,并構(gòu)建出對應(yīng)的RawEvent故觅。

EventHub處理inotify事件
// readNotify() will modify the list of devices so this must be done after
// processing all other events to ensure that we read all remaining events
// before closing the devices.
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
    // 標(biāo)識已經(jīng)處理過
    mPendingINotify = false;
    // 處理inotify事件
    readNotifyLocked();
    deviceChanged = true;
}
  
status_t EventHub::readNotifyLocked() {
    // 省略若干行
    // 從mINotifyFd讀取事件內(nèi)容
    res = read(mINotifyFd, event_buf, sizeof(event_buf));
    // 省略若干行
    // 遍歷每一個inotify_event
    while (res >= (int)sizeof(*event)) {
        event = (struct inotify_event*)(event_buf + event_pos);
        if (event->len) {
            if (event->wd == mInputWd) {
                // 是input類型的變更
                // 獲取設(shè)備對應(yīng)的文件路徑
                std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name);
                if (event->mask & IN_CREATE) {
                    // 是設(shè)備連入事件厂庇,則調(diào)用openDeviceLocked來添加設(shè)備
                    // 上面已經(jīng)介紹過,這里就不展開了
                    openDeviceLocked(filename.c_str());
                } else {
                    // 否則是設(shè)備斷開事件输吏,則調(diào)用closeDeviceByPathLocked關(guān)閉設(shè)備
                    ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
                    closeDeviceByPathLocked(filename.c_str());
                }
            }
            // 省略若干行
        }
        event_size = sizeof(*event) + event->len;
        res -= event_size;
        event_pos += event_size;
    }
    return 0;
}

這里首先會從mINotifyFd讀取對應(yīng)的inotify事件权旷,然后遍歷每一個event,判斷是設(shè)備接入還是斷開并分別進(jìn)行設(shè)備添加和移除的處理拄氯。

void EventHub::closeDeviceByPathLocked(const char* devicePath) {
    // 從device列表中根據(jù)設(shè)備路徑查找device
    Device* device = getDeviceByPathLocked(devicePath);
    if (device) {
        // 找到則調(diào)用closeDeviceLocked來關(guān)閉device
        // 上面reopen時已經(jīng)介紹過,這里不再展開
        closeDeviceLocked(device);
        return;
    }
    ALOGV("Remove device: %s not found, device may already have been removed.", devicePath);
}
  
EventHub::Device* EventHub::getDeviceByPathLocked(const char* devicePath) const {
    // 遍歷整個device列表
    for (size_t i = 0; i < mDevices.size(); i++) {
        Device* device = mDevices.valueAt(i);
        // 根據(jù)設(shè)備路徑配備device
        if (device->path == devicePath) {
            return device;
        }
    }
    return nullptr;
}

這里關(guān)閉設(shè)備它浅,首先是通過設(shè)備的路徑從device列表中查找對應(yīng)的device译柏,如果找到了,則調(diào)用closeDeviceLocked去處理設(shè)備的關(guān)閉姐霍。

小結(jié)

通過以上介紹香追,我們可以了解到EventHub的創(chuàng)建過程以及其采用epoll加inotify的方式來實(shí)現(xiàn)input設(shè)備以及input事件的監(jiān)聽轧拄;另外,在getEvents方法中,包含了整個設(shè)備的添加腻暮、刪除以及input事件的處理,而這些事件的處理正是基于EventHub創(chuàng)建時采用的epoll加inotify機(jī)制實(shí)現(xiàn)的盛龄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末航缀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子与纽,更是在濱河造成了極大的恐慌侣签,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件急迂,死亡現(xiàn)場離奇詭異影所,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)僚碎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門猴娩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事卷中∶” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵蟆豫,是天一觀的道長议忽。 經(jīng)常有香客問我,道長十减,這世上最難降的妖魔是什么栈幸? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮帮辟,結(jié)果婚禮上速址,老公的妹妹穿的比我還像新娘。我一直安慰自己由驹,他們只是感情好壳繁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著荔棉,像睡著了一般闹炉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上润樱,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天渣触,我揣著相機(jī)與錄音,去河邊找鬼壹若。 笑死嗅钻,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的店展。 我是一名探鬼主播养篓,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赂蕴!你這毒婦竟也來了柳弄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤概说,失蹤者是張志新(化名)和其女友劉穎碧注,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體糖赔,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡萍丐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了放典。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逝变。...
    茶點(diǎn)故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡基茵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出壳影,到底是詐尸還是另有隱情拱层,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布态贤,位于F島的核電站舱呻,受9級特大地震影響醋火,放射性物質(zhì)發(fā)生泄漏悠汽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一芥驳、第九天 我趴在偏房一處隱蔽的房頂上張望柿冲。 院中可真熱鬧,春花似錦兆旬、人聲如沸假抄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宿饱。三九已至,卻和暖如春脚祟,著一層夾襖步出監(jiān)牢的瞬間谬以,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工由桌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留为黎,地道東北人。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓行您,卻偏偏與公主長得像铭乾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子娃循,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容