Android Input输入事件处理流程分享(2)

努比亚技术团队原创内容,转载请务必注明出处。

  • Native层传递过程
    • InputEventReceiver的事件来源于哪里
    • InputConsumer
      • InputConsumer处理事件
      • InputConsumer的构建
    • InputChannel
      • InputChannel的创建
      • server端InputChannel的注册
      • client端InputChannel读取事件并传递
      • 小结
    • InputManagerService
      • IMS的创建
      • IMS的启动
      • 小结
    • InputDispatcher
      • InputDispatcher启动
      • InputDispatcher分发事件
    • InputReader(InputDispatcher事件的来源)
      • InputReader启动
      • InputReader处理事件
    • EventHub
      • EventHub的创建
      • EventHub如何获取输入事件
        • EventHub处理reopen设备
        • EventHub处理close设备
        • EventHub扫描设备
        • EventHub处理open设备
        • EventHub处理event
        • EventHub处理inotify事件
      • 小结

Native层传递过程

此小节主要介绍输入事件是如何从InputReader获取,然后InputDispatcher又是如何将它们分发出去,这个过程中使用什么技术进行事件的传递的。

Natvie事件传递时序图

InputEventReceiver的事件来源于哪里

上节中有介绍在Native层NativeInputEventReceiver的consumeEvents方法中会通过jni方式调用Java层的InputEventReceiver的dispatchInputEvent方法将事件传递到上层。那consumeEvents的事件又来源于哪里呢?我们继续看这个consumeEvents方法。

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

InputConsumer

consume方法中主要是从InputChannel获取输入事件的信息,然后根据消息中获取的事件类型构造出对应的event,并将消息中的事件信息赋值给event对象。

InputConsumer处理事件

从上面分析我们能够看到,再NativeInputEventReceiver的consumeEvents方法中,会循环调用InputConsumer的consume方法获取事件并进行处理。InputConsumer的consume方法中会通过InputChannel从socket中通过recv系统调用获取下层传递的事件,获取到事件后就会通过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.
            // 这里通过调用InputChannel的receiveMessage来获取消息
            status_t result = mChannel->receiveMessage(&mMsg);
            // 省略若干行
        }
        // 根据消息的类型生成不同的Event
        switch (mMsg.header.type) {
            case InputMessage::Type::KEY: {
                // 构造一个KeyEvent
                KeyEvent* keyEvent = factory->createKeyEvent();
                if (!keyEvent) return NO_MEMORY;
                // 从msg中获取事件的各属性,并赋值给构造出的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: {
                // 构造一个MotionEvent
                MotionEvent* motionEvent = factory->createMotionEvent();
                if (!motionEvent) return NO_MEMORY;
                updateTouchState(mMsg);
                // 从msg中获取事件的各属性,并赋值给构造出的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的构造和初始化,输入消息的获取随后再介绍。先看下factory->createMotionEvent,这里factory是PreallocatedInputEventFactory的实例。

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

好了,我们继续看event的初始化。这里主要是从msg中获取对应事件的详细信息然后赋值给对应的event对象上。

// 对key事件进行初始化
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事件进行初始化
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);
}

然后我们继续看msg的获取方法:InputChannel的receiveMessage方法。

status_t InputChannel::receiveMessage(InputMessage* msg) {
    ssize_t nRead;
    do {
        // 这里通过recv系统调用从socket中读取消息
        nRead = ::recv(mFd.get(), msg, sizeof(InputMessage), MSG_DONTWAIT);
    } while (nRead == -1 && errno == EINTR);
    // 省略若干行
    return OK;
}

可以看到这个方法主要是从socket中读取消息。那这里的socket是什么时候建立的呢?我们继续向下看。

InputConsumer的构建

在NativeInputEventReceiver的构造方法中,会创建出NativeInputEventReceiver,并将InputChannel传入。而NativeInputEventReceiver的构建是在Java层InputEventReceiver的native方法nativeInit中创建,并且能够看到,这里的InputChannel是从Java层传递下来的。

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

我们发现在InputConsumer构造时对InputChannel进行了初始化,那就继续超前看InputConsumer在哪里构建的。

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中,发现它的构造方法中传入了InputChannel,那么继续看NativeInputEventReceiver的构建。

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    // 通过jni获取java创建的InputChannel
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    // 省略若干行
    // 构建出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());
}

通过上述分析,我们发现NativeInputEventReceiver中获取底层事件的InputChannel是来自于Java层的传递,那么,InputChannel又是如何创建的呢?

InputChannel

InputChannel会作为句柄传递到下层,后面分发事件的时候会通过它来进行。而且这里会创建出两个,一个作为server端注册到InputManagerService,最终会注册到InputDispatcher中去,另一个则作为client端来接收server端的事件。

InputChannel的创建

通过前面分析,我们发现NativeInputEventReceiver中的InputChanel来源于Java层的InputChannel。上述nativeInit是Java层InputEventReceiver的native方法,继续看Java层的InputEventReceiver。

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

Java层InputEventReceiver构造时传入了InputChannel。在ViewRootImpl的setView方法中会创建InputChannel,然后会调用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();
            }
            // 省略若干行
            // 调用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方法会继续调用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) {
    // 直接调用WindowManagerService的addWindow方法
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
            outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
            outInsetsState, outActiveControls, userId);
}

addWindow方法中会调用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) {
        // 这里会调用WindowState的openInputChannel来打开inputChannel
        win.openInputChannel(outInputChannel);
    }
    // 省略若干行
    return res;
}

继续看WindowState的openInputChannel方法。首先会通过调用InputChannel的静态方法openInputChannelPair来创建两个InputChannel,一个作为client一个作为server;然后还会调用InputManagerService的registerInputChannel来注册server端的InputChannel;最后将client端的InputChannel设置到outInputChannel中。

void openInputChannel(InputChannel outInputChannel) {
    if (mInputChannel != null) {
        throw new IllegalStateException("Window already has an input channel.");
    }
    String name = getName();
    // 通过openInputChannelPair方法创建出两个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设置到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方法中会直接调用InputChannel的native方法nativeOpenInputChannelPair来创建出一对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 + "'");
    }
    // 继续调用natvie方法创建出两个InputChannel
    return nativeOpenInputChannelPair(name);
}

jni方法nativeOpenInputChannelPair中会继续调用InputChannel的openInputChannelPair静态方法。然后将创建出的两个inputChannel分别添加到数组中,然后返回给上层。

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;
    // 创建出server端和client端的InputChannel
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
    // 省略若干行
    // 添加到数组中,然后返回给上层
    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

openInputChannelPair方法中会首先通过socketpair创建一对相互连接的套接字,然后分别给socket设置相应的选项值;然后通过InputChannel的create方法创建出两个分别与socket关联的inuptChannel。

status_t InputChannel::openInputChannelPair(const std::string& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    // 创建一对相互连接的socket
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        status_t result = -errno;
        // 创建失败做相应的处理
        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
                name.c_str(), errno);
        outServerChannel.clear();
        outClientChannel.clear();
        return result;
    }
  
    // 分别设置两个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]);
    // 创建出server端InputChannel,并于socket关联
    outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);
  
    std::string clientChannelName = name + " (client)";
    android::base::unique_fd clientFd(sockets[1]);
    // 创建出client端InputChannel,并于socket关联
    outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
    return OK;
}

通过InputChannel的create方法构建出InputChannel并返回。

sp<InputChannel> InputChannel::create(const std::string& name, android::base::unique_fd fd,
                                      sp<IBinder> token) {
    // 设置文件描述符fd的状态属性为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;
    }
    // 创建出InputChannel并返回
    return new InputChannel(name, std::move(fd), token);
}

至此,InputChannel便创建并关联上socket上了。并且通过前面的介绍,我们知道了获取输入事件时是从client端的socket中读取消息并进行事件封装,然后传递到上层。但是这里我们发现有一个问题,就是client端socket中的数据是从哪里来的呢?我们继续看一下WindowState的openInputChannel方法。

server端InputChannel的注册

在通过openInputChannel开启InputChannel后,会调用了InputManagerService的registerInputChannel方法注册server端的InputChannel

server端InputChannel的注册
void openInputChannel(InputChannel outInputChannel) {
    // 省略若干行
    // 通过openInputChannelPair方法创建出两个InputChannel
    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
    mInputChannel = inputChannels[0];
    mClientChannel = inputChannels[1];
    // 注册server端的InputChannel到InputManagerService中
    mWmService.mInputManager.registerInputChannel(mInputChannel);
    // 省略若干行
}

我们发现server端的InputChannel被注册到了InputManagerService中去了,那么,我们继续向下看。

public void registerInputChannel(InputChannel inputChannel) {
    if (inputChannel == null) {
        throw new IllegalArgumentException("inputChannel must not be null.");
    }
    // 调用native方法继续注册
    nativeRegisterInputChannel(mPtr, inputChannel);
}

在InputManagerService的registerInputChannel方法中直接调用了native方法nativeRegisterInputChannel,我们继续。

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);
    // 设置dispose的callback,在inputChannel
    // dispose之后会调用函数指针handleInputChannelDisposed
    // 来调用NativeInputManager的unregisterInputChannel
    // 解注册inputChannel
    android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
            handleInputChannelDisposed, im);
}

在native方法中,先调用了NativeInputManager的registerInputChannel方法注册inputChannel,然后会给inputChannel设置dispose callback,并且callback中执行了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构建出Connection,然后将其添加到注册列表当中。

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);
        // 省略若干行
        // 创建connection并添加的注册列表中
        sp<Connection> connection = new Connection(inputChannel, false /*monitor*/, mIdGenerator);
        int fd = inputChannel->getFd();
        mConnectionsByFd[fd] = connection;
        mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel;
        // 将inputChannel的fd添加到looper中,并且对应的event是ALOOPER_EVENT_INPUT
        // 传入的looper callback为handleReceiveCallback方法,
        // 因此当事件到来时,会触发此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端就可以读取到了。但是,这里还发现存在一个问题:那就是server端写入事件消息后,怎么通知到client去开始处理呢?我们在回过头来看一下前面介绍的InputEventReceiver的构造函数。

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的构造方法中调用了native方法nativeInit进行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实例自身,所以,当server端写入事件消息时,就会触发callback,于是便调用到NativeInputEventReceiver的handleEvent方法。

status_t NativeInputEventReceiver::initialize() {
    // 设置文件描述符对应的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中
            // 对应的event为ALOOPER_EVENT_INPUT
            // 并传入了this作为loopercallback
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}

我们发现在handleEvent方法中,调用了consumeEvents方法来处理事件,而consumeEvents方法便是我们前面介绍过了的,在其内部会通过jni的方式将事件向Java层传递到InputEventReceiver的dispatchInputEvent,从而便实现了事件的分发。

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

小结

通过以上分析,我们便明白了InputDispatcher是如果通过InputChannel将事件向上层进行分发的整个过程。首先是创建一对InputChannel,并且会开启一对相互连接的socket作为事件传递的媒介。server端的InputChannel会注册到InputDispatcher中去以完成事件的分发,并且会将其fd添加到looper中,而client端的InputChannel会在InputEventReceiver初始化时也会将其fd添加到looper中,并传入callback类接收server端写入的事件,这样整个过程便串联起来了。但是,这里还存在一个问题:InputDispatcher的事件从哪里来呢?

InputManagerService

InputManagerService简称IMS,和其他系统服务一样,是在SystemServer中创建并启动,它主要是用来监测和加工输入事件,并向上层传递。而且,上文所说的InputDispatcher以及InputReader均是在InputManagerService中构建出来的。

IMS的创建

在SystemServer的startOtherServices方法中,直接通过new的方式创建出IMS实例。

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

InputManagerService的构造方法中,会先创建出Handler,然后通过native方法nativeInit来实现IMS的初始化,主要是构建native层的IMS。

public InputManagerService(Context context) {
    this.mContext = context;
    // 创建出handler
    this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
    // 省略若干行
    // 调用native方法来构建native层IMS
    mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    // 省略若干行
}

native方法中先获取到上层传下来的messageQueue,然后获取对应的Looper,并构建出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;
    }
    // 构建NativeInputManager
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

NativeInputManager构造中,先创建出native层IMS实例,然后将其添加到serviceManager中。

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

在InputManager构建时,会分别创建出InputDispatcher、InputListener以及InputReader实例。这里将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);
}

通过以上分析,我们发现在IMS创建的最后,会创建出InputDispatcher和InputReader,InputDispatcher我们前面已经介绍了,主要是用于分发事件;而InputReader是用来获取底层输入事件的,这个我们后面会介绍到。

IMS的启动

我们继续来看SystemServer的startCoreServices方法,在创建出IMS实例后,会调用其的start方法来启动服务。

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    // 省略若干行
    t.traceBegin("StartInputManager");
    // 将WindowCallback传递给IMS
    inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
    // 调用start启动服务
    inputManager.start();
    t.traceEnd();
    // 省略若干行
}

start方法中会直接调用native的nativeStart方法来启动native层的IMS。

public void start() {
    Slog.i(TAG, "Starting input manager");
    // 调用native方法来启动底层IMS
    nativeStart(mPtr);
    // 省略若干行
}

nativeStart方法中会获取到InputManager,然后调用它的start方法。

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

在InputManager的start方法中,先调用了InputDispatcher的start方法来启动InputDispatcher,然后调用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;
}

小结

通过以上IMS的创建和启动过程分析,我们能够看到在IMS的创建和启动都是在SystemServer的startCoreServices方法中触发的,另外在创建的时候也会分别创建出InputDispatcher和InputReader;而且,在调用start方法启动的时候,最终也会触发调用InputDispatcher和InputReader的start方法来启动各自实例。

InputDispatcher

通过上述分析,知道了InputDispatcher的创建是在IMS创建时创建,那么它是如何启动起来的呢?我们继续看InputDispatcher的start方法。

InputDispatcher启动

在InputDispatcher的start方法中,会创建出InputThread线程,并传入了两个函数指针:dispatchOnce以及mLooper->wake。

status_t InputDispatcher::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    // 直接构造出Thread,传入两个回调函数
    mThread = std::make_unique<InputThread>(
            "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
    return OK;
}

继续看InputThread的构造过程,发现初始化列表中对传入的回调函数进行了保存,然后构建InputThreadImpl并调用其run方法将线程启动起来。

InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
    // 这里保存wake回调函数
      : mName(name), mThreadWake(wake) {
    // 将loop函数传入InputThreadImpl
    mThread = new InputThreadImpl(loop);
    mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
}
  
InputThread::~InputThread() {
    mThread->requestExit();
    // 调用wake函数
    if (mThreadWake) {
        mThreadWake();
    }
    mThread->requestExitAndWait();
}
  
class InputThreadImpl : public Thread {
public:
    explicit InputThreadImpl(std::function<void()> loop)
                                            // 保存loop函数
          : Thread(/* canCallJava */ true), mThreadLoop(loop) {}
  
    ~InputThreadImpl() {}
  
private:
    std::function<void()> mThreadLoop;
  
    bool threadLoop() override {
        // 在线程的loop循环中调用了传入的loop函数。
        mThreadLoop();
        // 返回true线程会一直运行,直到requestExit被调用时退出
        return true;
    }
};

通过以上分析,我们发现InputThread构造时会创建出线程并将其启动起来,传入的loop函数(dispatchOnce)最终会作为线程的loop来执行,而wake函数(mLooper->wake)也会在InputThread析构时调用。

InputDispatcher分发事件

通过前面的介绍,我们了解到在InputDispatcher启动时创建了线程,并且将dispatchOnce作为线程的执行函数传入到InputThread中。所以,当InputDispatcher线程被唤醒后就会执行dispatchOnce方法来分发事件。

InputDispatcher分发事件

我们继续,在dispatchOnce方法中,首先会判断是否有command需要处理(如:configChanged,focusChanged等),如果有就会调用runCommandsLockedInterruptible方法执行所有command,然后会再次触发wake执行事件的处理;如果没有则直接调用dispatchOnceInnerLocked来处理输入事件;最后,looper会再次进入睡眠等待下一次唤醒。

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需要处理,就开始分发事件
            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.
        // 检测是否事件分发出现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);
    // 处理完成后调用looper的pollOnce进入睡眠状态,等待下一次唤醒,
    // 如果是处理了command,则这个timeoutMillis为0
    // 所以会接着执行一次loop
    mLooper->pollOnce(timeoutMillis);
}

dispatchOnceInnerLocked方法会先判断是否有待分发的事件,没有则从事件队列中取出一个事件;然后根据事件不同的type调用不同的dispatch方法进行事件分发。

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) {
        // 如果没有待分发的事件
        if (mInboundQueue.empty()) {
            // 省略若干行
            // Nothing to do if there is no pending event.
            // 事件队列为空,并且没有待分发的事件,直接返回
            if (!mPendingEvent) {
                return;
            }
        } else {
            // Inbound queue has at least one entry.
            // 从队列中取出一个事件
            mPendingEvent = mInboundQueue.front();
            mInboundQueue.pop_front();
            traceInboundQueueLengthLocked();
        }
        // 省略若干行
    switch (mPendingEvent->type) {
        // 省略若干行
        // 根据事件的type分别进行处理
        case EventEntry::Type::KEY: {
            KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
            // 省略若干行
            // 分发key事件
            done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
            break;
        }
  
        case EventEntry::Type::MOTION: {
            // 省略若干行
            // 分发motion事件
            done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
            break;
        }
    }
}

这里以key事件为例继续介绍,dispatchKeyLocked中首先通过findFocusedWindowTargetsLocked方法查找到焦点窗口,然后调用dispatchEventLocked朝焦点窗口上分发事件。

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);
    // 省略若干行
    // 将事件分发到对应window上去
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

dispatchEventLocked方法中会遍历所有查找到的focus窗口(inputTarget),然后通过inputChannel获取到链接对象connection,最后通过prepareDispatchCycleLocked将事件分发出去。

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) {
            // 开始事件分发
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
        }
        // 省略若干行
    }
}

prepareDispatchCycleLocked方法中先判断是否需要split motion事件并进行处理,最后调用enqueueDispatchEntriesLocked方法将待分发的事件添加到mOutboundQueue队列中。

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
                                                 const sp<Connection>& connection,
                                                 EventEntry* eventEntry,
                                                 const InputTarget& inputTarget) {
    // 省略若干行
    // Split a motion event if needed.
    // 如果需要split motion事件则进行处理
    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.
    // 将将要分发的事件入队
    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}

enqueueDispatchEntriesLocked方法中会分别处理不同的flag对应的事件将其添加到outboundQueue中,最后通过调用startDispatchCycleLocked开始事件的分发。

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
                                                   const sp<Connection>& connection,
                                                   EventEntry* eventEntry,
                                                   const InputTarget& inputTarget) {
    // 省略若干行
  
    bool wasEmpty = connection->outboundQueue.empty();
    // 分别处理不同flag对应的event,并将其添加到outboundQueue队列中
    // 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被添加到队列则开始处理
        startDispatchCycleLocked(currentTime, connection);
    }
}

startDispatchCycleLocked方法中通过遍历outboundQueue队列,取出所有的event,然后根据其type分别调用InputPublisher的publishXxxEvent将事件分发出去。

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
                                               const sp<Connection>& connection) {
    // 省略若干行
    // 循环遍历outboundQueue队列
    while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
        // 从outboundQueue队列取出事件
        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;
        // 根据event的不同type分别进行分发
        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.
                // 分发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;
                // 省略若干行
                // 分发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事件为例继续介绍,在publishKeyEvent方法中,首先会根据传入的event详细信息构建出InputMessage,然后再调用InputChannel的sendMessage方法将msg发送出去。

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) {
    // 省略若干行
    // 根据event信息构建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发送出去
    return mChannel->sendMessage(&msg);
}

sendMessage主要就是先copy一份事件msg,然后调用send将msg循环写入socket,从而实现输入事件的分发。

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循环写入msg
        nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);
    // 省略若干行
    return OK;
}

InputReader(InputDispatcher事件的来源)

InputDispatcher中的事件是从InputReader中来的,InputReader从EventHub中获取到输入事件后,会通过调用InputDispatcher的notifyXxx方法来将事件传递到InuptDispatcher中。

InputReader启动

在IMS的start方法中会调用InputReader的start方法来启动InputReader,我们继续看InputReader的start方法。在start方法中,会创建出InputThread线程,这里注意,创建线程时传入了两个函数指针(laumda表达式):loopOnce和mEventHub->wake。通过上面对InputThread的介绍,我们知道最终,loopOnce会作为线程的循环方法进行调用,而mEventHub->wake最终也会在线程析构时触发。

status_t InputReader::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    // 直接构造出Thread,传入两个回调函数
    mThread = std::make_unique<InputThread>(
            "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
    return OK;
}

InputReader处理事件

InputReader在其线程的threadLoop中会调用loopOnce从EventHub中获取输入事件,如果获取到事件,则继续调用processEventsLocked进行处理。接着会调用到InputDevice -> InputMapper -> InputDispatcher(InputListenerInterface),在InputDispatcher中触发notifyXxx方法,从而将事件分发出去。

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();
        // 获取到输入事件则调用processEventsLocked进行处理
        if (count) {
            processEventsLocked(mEventBuffer, count);
        }
    // 省略若干行
}

processEventsLocked方法中会根据事件的type,分别处理device的变更事件以及输入事件。输入事件则继续调用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事件则继续处理
            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中根据eventHubId查找device,如果找到则调用对应device的process方法继续处理。

void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
                                               size_t count) {
    // 通过eventHubId从map中查找InputDevice
    auto deviceIt = mDevices.find(eventHubId);
    if (deviceIt == mDevices.end()) {
        // 没有对应的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;
    }
    // 调用InputDevice的process继续处理事件
    device->process(rawEvents, count);
}

InputDevice的process中会遍历所有的event,并且根据event中的deviceId从mDevices中找到对应的device,然后遍历其所有的InputMapper,并调用mapper的process进行事件处理。

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中找到对应的device,然后遍历其所有inputMapper,并调用其process方法进行处理
        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);
    // 查找对应的device
    if (deviceIt != mDevices.end()) {
        auto& devicePair = deviceIt->second;
        auto& mappers = devicePair.second;
        // 遍历该device的所有InputMapper,并调用函数指针f
        for (auto& mapperPtr : mappers) {
            f(*mapperPtr);
        }
    }
}

InputMapper在InputReader中处理device接入事件触发时会调用addDeviceLocked方法,然后会调用到createDeviceLocked方法来创建出对应的InputDevice,创建出device后,便调用它的addEventHubDevice来创建出相应的InputMapper并添加到全局map中。

void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
    // 根据eventHubId查找device
    if (mDevices.find(eventHubId) != mDevices.end()) {
        ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);
        return;
    }
  
    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
    // 创建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已经存在则直接返回
        device = deviceIt->second;
    } else {
        // 否则创建出对应的InputDevice
        int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();
        device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
                                               identifier);
    }
    // 调用addEventHubDevice,构建出相应的mapper
    device->addEventHubDevice(eventHubId);
    return device;
}

通过addEventHubDevice方法,可以看出针对不同的device类型,会构建出不同的mapper,最后将mapper数组添加到了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方法中,循环遍历了所有的mapper并调用其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或者游戏面板对应的key
            if (isKeyboardOrGamepadKey(scanCode)) {
                processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
            }
            break;
        }
        // 省略若干行
    }
}

processKey方法中,会根据event是否为down以及event的其他属性构建出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;
    // 省略若干行
    // 根据event内容构建相应的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,并调用其notifyKey方法传递key事件
    getListener()->notifyKey(&args);
}

notifyKey方法中首先会构建出KeyEvent事件对象,并通过IMS传递到Java层的interceptKeyBeforeQueueing方法;然后根据args构建KeyEnvtry,并将其添加到mInboundQueue队列中;最后调用wake方法唤醒looper。

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
    // 省略若干行
    // 根据args构建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;
    // 调用IMS的interceptKeyBeforeQueueing
    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
    // 省略若干行
    // 构建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队列中,然后如果需要wake就唤醒looper,然后就会触发threadLoop,从而调用dispatchOnce方法回到InputDispatcher中分发事件。

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

EventHub

通过前面InputReader的介绍,我们发现输入事件的源头是通过调用EventHub的getEvents方法获取的。那么,EventHub是如何创建以及进行事件的获取的呢?

EventHub获取事件

EventHub的创建

我们回到InputReader的构造方法,发现在InputReader构造方法的初始化列表中,会赋值全局变量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进行了初始化,通过前面介绍我们知道,InputReader是在InputManager中构建出来的,那么我们继续看。

InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = createInputDispatcher(dispatcherPolicy);
    mClassifier = new InputClassifier(mDispatcher);
    // 通过createInputReader创建出InputReader
    mReader = createInputReader(readerPolicy, mClassifier);
}
  
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,
                                           const sp<InputListenerInterface>& listener) {
                          // 这里直接通过std::make_unique构建出EventHub实例
    return new InputReader(std::make_unique<EventHub>(), policy, listener);
}

在InputManager中通过createInputReader构建出InputReader实例,而在createInputReader方法中,会首先通过std::make_unique构建出EventHub实例,继续看EventHub的构造函数。

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();
    // 创建出epoll
    mEpollFd = epoll_create1(EPOLL_CLOEXEC);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
    // 创建inotify
    mINotifyFd = inotify_init();
    // 通过inotify来监听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);
    // 创建管道
    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];
    // 设置管道读取端非阻塞属性
    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
                        errno);
    // 设置管道写入端非阻塞属性
    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的构造方法中,我们可以看到:首先会创建出epoll,然后创建出inotify来监听/dev/input路径下文件的增删,并将inotify添加到epoll中进行监听,还会创建出一个管道,并将管道读取端也添加到epoll中。这样当有新的输入设备接入或者删除事,就会触发唤醒epoll进行处理。

EventHub如何获取输入事件

在上面介绍的InputReader中,我们了解到loopOnce方法中通过调用EventHub的getEvents来获取输入事件。那么,我们继续看getEvents方法,此方法比较长,我们先看下大概的框架。

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    for (;;) {
        // Reopen input devices if needed.
        if (mNeedToReopenDevices) {
            // 如果存在需要reopen的设备,则先关闭所有device
            // 然后设置需要scan设备的标识
        }
  
        // Report any devices that had last been added/removed.
        while (mClosingDevices) {
            // 如果存在需要关闭的设备,则遍历所有需要关闭的设备链表,
            // 删除对应的device,并构建event
        }
        // 需要扫描device,则调用scanDevicesLocked方法扫描
        // 最后更新device列表
        if (mNeedToScanDevices) {
        }
        //存在需要open的device,则更新mOpeningDevices链表
        // 并构建event
        while (mOpeningDevices != nullptr) {
        }
        // 需要scanFinish事件,则构建对应event
        if (mNeedToSendFinishedDeviceScan) {
        }
  
        // Grab the next input event.
        // 遍历需要处理的事件列表
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            if (eventItem.data.fd == mINotifyFd) {
                // 如果是inotify事件,则修改对应标识,后面会扫描处理对于的变更
            }
  
            if (eventItem.data.fd == mWakeReadPipeFd) {
                // 管道事件,则设置wake为true,跳出循环继续执行
            }
            // 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);
        // 唤醒开始执行时则加锁
        mLock.lock(); // reacquire lock after poll
    }
  
    // All done, return the number of events we read.
    return event - buffer;
}

通过以上getEvents方法的大致流程,能够看到首先会查看是否有需要reopen的device并进行处理,接着处理需要close的device,然后是判断是否需要扫描设备并进行device扫描;接着处理新接入的设备,然后开始遍历待处理的事件,并分别处理inotify、管道以及真正的输入事件;过程中如果有event被处理则就会break掉for循环继续进行下一次处理,如果所有事件都已处理完就会走到下面的epoll_wait进入wait状态等待唤醒。

EventHub处理reopen设备
// Reopen input devices if needed.
if (mNeedToReopenDevices) {
    // 设置mNeedToReopenDevices为false,避免下次循环继续处理
    mNeedToReopenDevices = false;
  
    ALOGI("Reopening all input devices due to a configuration change.");
    // 关闭所有device
    closeAllDevicesLocked();
    // 标识需要扫描device,后面循环会进行扫描设备
    mNeedToScanDevices = true;
    // 跳出for循环,继续后续处理
    break; // return to the caller before we actually rescan
}

处理reopen设备,首先是重置reopen标识,然后调用closeAllDevicesLocked来关闭所有的device,接着标识设备需要扫描,最后break退出此次循环,继续下一次循环处理。继续看closeAllDevicesLocked方法:

void EventHub::closeAllDevicesLocked() {
    mUnattachedVideoDevices.clear();
    while (mDevices.size() > 0) {
        // 循环遍历所有device,并调用closeDeviceLocked来进行关闭
        closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1));
    }
}
  
void EventHub::closeDeviceLocked(Device* device) {
    // 省略若干行
    // 从epoll移除此device的监听
    unregisterDeviceFromEpollLocked(device);
    // 省略若干行
    // 从device列表中移除此设备
    mDevices.removeItem(device->id);
    // 关闭device
    device->close();
  
    // Unlink for opening devices list if it is present.
    Device* pred = nullptr;
    bool found = false;
    // 从已经打开的device列表中查找对应的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;
        }
        // 删除对应device
        delete device;
    } else {
        // Link into closing devices list.
        // The device will be deleted later after we have informed the client.
        // 打开的device列表中没找到,则将device添加到待移除的设备列表中
        device->next = mClosingDevices;
        mClosingDevices = device;
    }
}
EventHub处理close设备

关闭device时首先从epoll中删除对应的监听并从device列表中将其移除,然后在已经打开的device列表中查找,如果找到则将其从open的device列表中移除,否则就将其添加到close的device列表中去,后面会处理close列表。这里我们继续看下epoll移除device的unregisterDeviceFromEpollLocked方法:

status_t EventHub::unregisterDeviceFromEpollLocked(Device* device) {
    if (device->hasValidFd()) {
        // 如果设备存在有效的fd,则调用unregisterFdFromEpoll将其从epoll中移除
        status_t result = unregisterFdFromEpoll(device->fd);
    }
    return OK;
}
  
status_t EventHub::unregisterFdFromEpoll(int fd) {
    // 调用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;
}

接着我们继续看getEvents中对带关闭设备的处理过程:

// Report any devices that had last been added/removed.
// 遍历所有需要关闭的device链表
while (mClosingDevices) {
    Device* device = mClosingDevices;
    ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
    // 移动表头到到下一个位置
    mClosingDevices = device->next;
    // 构建设备移除的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;
    // 标识需要构建扫描完成的条件
    mNeedToSendFinishedDeviceScan = true;
}

处理关闭的device,首先是遍历整个需要关闭的device链表,并依次对每一个device,构造设备移除的event,然后删除对应的device,最后标识需要构建扫描完成的事件条件,待后面添加扫描完成的event。

EventHub扫描设备

前面如果有处理reopen设备,则会关闭所有设备,并设置需要扫描设备的标识,然后这里会调用scanDevicesLocked方法来扫描device。

if (mNeedToScanDevices) {
    // 重置需要扫描的标识,避免下一次继续扫描设备
    mNeedToScanDevices = false;
    // 开始扫描设备
    scanDevicesLocked();
    // 标识后面需要有扫描完成的event
    mNeedToSendFinishedDeviceScan = true;
}

扫描设备会调用scanDevicesLocked方法进行扫描处理,我们继续看:

void EventHub::scanDevicesLocked() {
    // 继续调用scanDirLocked来扫描设备,这里传入的路径为/dev/input
    status_t result = scanDirLocked(DEVICE_PATH);
    if (result < 0) {
        ALOGE("scan dir failed for %s", DEVICE_PATH);
    }
    // 省略若干行
    // 如果存在虚拟的键盘,则在这里创建虚拟键盘
    if (mDevices.indexOfKey(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) < 0) {
        createVirtualKeyboardLocked();
    }
}

首先调用scanDirLocked扫描/dev/input目录来索引可用的device,然后判断如果存在虚拟的键盘,则调用createVirtualKeyboardLocked方法来创建虚拟键盘设备。

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);
    }
    // 关闭目录
    closedir(dir);
    return 0;
}

扫描device主要是扫描/dev/input目录,遍历每一个设备文件并调用openDeviceLocked方法来打开对应的device,最后关闭目录。

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);
    // 省略若干行
    // 然后依次获取设备的名称、驱动版本、设备的厂商等信息、物理路径、唯一的id等信息
    // 接着判断是键盘或者游戏面板、鼠标等设备类型进行特殊处理
    // 最后将设备添加到epoll中进行监听
    if (registerDeviceForEpollLocked(device) != OK) {
        // 添加失败则删除设备并退出
        delete device;
        return -1;
    }
    // 省略若干行
    // 将设备添加到device列表
    addDeviceLocked(device);
    return OK;
}

openDeviceLocked方法中,首先通过open方法打开对应的设备文件,然后会获取设备的各种信息并进行相应的处理,接着通过registerDeviceForEpollLocked方法将device添加到epoll中去,最后再通过addDeviceLocked方法将device添加到设备列表当中去。

status_t EventHub::registerDeviceForEpollLocked(Device* device) {
    // 省略若干行
    // 调用registerFdForEpoll将设备描述符添加到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 = {};
    // 设置event类型为EPOLLIN 和 EPOLLWAKEUP
    eventItem.events = EPOLLIN | EPOLLWAKEUP;
    eventItem.data.fd = fd;
    // 通过epoll_ctl调用并传入EPOLL_CTL_ADD的flag添加对应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) {
    // 将设备添加到device列表中
    mDevices.add(device->id, device);
    // 将device添加到open的设备链表中
    device->next = mOpeningDevices;
    mOpeningDevices = device;
}

我们能够看到在registerFdForEpoll方法中,设备的fd被添加为EPOLLIN和EPOLLWAKEUP类型的,所以这两种类型的事件到来时就可以唤醒epoll工作,然后在addDeviceLocked方法中会将设备添加到device列表和open的device链表中去。

EventHub处理open设备

在getEvents方法中,会遍历整个open的设备链表,迭代每个设备,然后构建设备添加的event,最后标识扫描完成的变量;如果在处理过程中,buffer已经满了,则会break掉,未处理的设备会在下一次迭代时继续处理。

// 迭代每一个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;
    // 构建DEVICE_ADDED的event
    event->when = now;
    event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
    event->type = DEVICE_ADDED;
    event += 1;
    // 设置scan完成标识
    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变更,则标识mPendingINotify,后面会进行处理
        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()");
            // 标识被唤醒,后面epoll就不会进入wait状态
            awoken = true;
            char buffer[16];
            ssize_t nRead;
            do {// 从管道中读取出消息内容
                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中的设备描述符获取对应device
    Device* device = getDeviceByFdLocked(eventItem.data.fd);
    // 省略若干行
    // This must be an input event
    if (eventItem.events & EPOLLIN) {
        // event是input事件
        // 从device中读取出事件内容
        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);
            // 出错,则关闭对应device,并标识设备发生变更
            deviceChanged = true;
            closeDeviceLocked(device);
        }
        // 省略若干行
        else {
            // 获取deviceId
            int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            // 遍历读取到的所有event,并构建出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时,首先处理设备的变更事件,然后会处理wake管道事件,最后才会处理真正的input事件;处理input事件时会遍历每一个获取到的event,并构建出对应的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) {
    // 标识已经处理过
    mPendingINotify = false;
    // 处理inotify事件
    readNotifyLocked();
    deviceChanged = true;
}
  
status_t EventHub::readNotifyLocked() {
    // 省略若干行
    // 从mINotifyFd读取事件内容
    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类型的变更
                // 获取设备对应的文件路径
                std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name);
                if (event->mask & IN_CREATE) {
                    // 是设备连入事件,则调用openDeviceLocked来添加设备
                    // 上面已经介绍过,这里就不展开了
                    openDeviceLocked(filename.c_str());
                } else {
                    // 否则是设备断开事件,则调用closeDeviceByPathLocked关闭设备
                    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读取对应的inotify事件,然后遍历每一个event,判断是设备接入还是断开并分别进行设备添加和移除的处理。

void EventHub::closeDeviceByPathLocked(const char* devicePath) {
    // 从device列表中根据设备路径查找device
    Device* device = getDeviceByPathLocked(devicePath);
    if (device) {
        // 找到则调用closeDeviceLocked来关闭device
        // 上面reopen时已经介绍过,这里不再展开
        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);
        // 根据设备路径配备device
        if (device->path == devicePath) {
            return device;
        }
    }
    return nullptr;
}

这里关闭设备,首先是通过设备的路径从device列表中查找对应的device,如果找到了,则调用closeDeviceLocked去处理设备的关闭。

小结

通过以上介绍,我们可以了解到EventHub的创建过程以及其采用epoll加inotify的方式来实现input设备以及input事件的监听;另外,在getEvents方法中,包含了整个设备的添加、删除以及input事件的处理,而这些事件的处理正是基于EventHub创建时采用的epoll加inotify机制实现的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容