fwrite

fwrite

好好生活
twitter
github
email

Input输入事件处理流程

安卓中输入事件主要分为 KeyEvent 和 MotionEvent 两种

传递流程#

webp

这里首先 eventhub 构建的时候会遍历整个 /dev/input 路径下的 fd,并将其添加到 epoll 中,同时还会监听此路径下新的设备的创建和卸载。当 driver 向特定描述符写入事件后,会触发唤醒 epoll 起来工作,这时候 eventHub 通过 read 方法从描述符中读取原始事件,然后通过简单封装成 rawEvent 并传递给 InputReader。
InputReader 中的 threadLoop 中会调用 eventHub 的 getEvents 来获取输入事件,然后通过调用 notifyxxx 方法将事件传递到 InputDispater 并最终通过 notifyxxx 方法传递到上层。

Java 层事件传递流程#

Input 输入事件处理流程

Native 传递事件到 Java#

在 android_view_InputEventReceiver 中的 consumeEvents 方法中会从 InputConsumer 中获取 input 事件,然后通过 jni 将事件向上层传递。

webp-1720679461808-171

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
    if (kDebugDispatchCycle) {
        ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%" PRId64,
              getInputChannelName().c_str(), toString(consumeBatches), frameTime);
    }
    // 省略若干行
    // 这里通过InputConsumer的consume方法获取到inputevent
    status_t status = mInputConsumer.consume(&mInputEventFactory,
            consumeBatches, frameTime, &seq, &inputEvent,
            &motionEventType, &touchMoveNum, &flag);
    // 省略若干行
    if (inputEventObj) {
        if (kDebugDispatchCycle) {
            ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName().c_str());
        }
        // 此处通过jni调用InputEventReceiver的dispatchInputEvent方法进行事件的分发,
        // 从而将input事件传递到java层
        env->CallVoidMethod(receiverObj.get(),
                gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
        if (env->ExceptionCheck()) {
            ALOGE("Exception dispatching input event.");
            skipCallbacks = true;
        }
        env->DeleteLocalRef(inputEventObj);
    } else {
        ALOGW("channel '%s' ~ Failed to obtain event object.",
                getInputChannelName().c_str());
        skipCallbacks = true;
    }
  
    if (skipCallbacks) {
        mInputConsumer.sendFinishedSignal(seq, false);
    }
}
 

InputEventReceiver 分发事件#

在 InputEventReceiver 中的 dispatchInputEvent 方法中会调用 onInputEvent 方法进行事件的处理,InputEventReceiver 是抽象类,它的一个子类 WindowInputEventReceiver 是用来处理 input 事件的,WindowInputEventReceiver 是 frameworks/base/core/java/android/view/ViewRootImpl.java 的内部类,它复写了 onInputEvent 方法,该方法中会调用 enqueueInputEvent 方法对事件进行入队。

webp-1720679507371-174

Java 层事件入口#
private void dispatchInputEvent(int seq, InputEvent event) {
    mSeqMap.put(event.getSequenceNumber(), seq);
    // 直接调用onInputEvent
    onInputEvent(event);
}
  
public void onInputEvent(InputEvent event) {
    // 直接调用finishInputEvent回收事件,所以此方法需要子类复写
    finishInputEvent(event, false);
}

dispatchInputEvent 方法是 jni 直接调用的方法,属于 Java 层的入口方法,其中会直接调用 onInputEvent 方法,onInputEvent 方法中直接调用了 finishInputEvent 回收事件,所以就需要子类去实现具体的分发逻辑。

对事件进行兼容性处理#

onInputEvent 方法中首先调用 InputCompatProcessor 的 processInputEventForCompatibility 方法对事件进行兼容性处理,这个方法中会判断应用的 targetSdkVersion 如果小于 M 并且是 motion 事件则进行兼容处理并返回,否则返回 null;然后会调用 enqueueInputEvent 方法对事件进行入队。

@Override
public void onInputEvent(InputEvent event) {
    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
    List<InputEvent> processedEvents;
    try {
        // 这块儿主要是对低版本进行兼容性处理
        processedEvents =
            mInputCompatProcessor.processInputEventForCompatibility(event);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
    if (processedEvents != null) {
        // 安卓M及以下版本,在这里处理
        if (processedEvents.isEmpty()) {
            // InputEvent consumed by mInputCompatProcessor
            finishInputEvent(event, true);
        } else {
            for (int i = 0; i < processedEvents.size(); i++) {
                enqueueInputEvent(
                        processedEvents.get(i), this,
                        QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
            }
        }
    } else {
        // 这里对事件进行入队
        enqueueInputEvent(event, this, 0, true);
    }
}
  
public InputEventCompatProcessor(Context context) {
    mContext = context;
    // 获取应用的targetsdk版本
    mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
    mProcessedEvents = new ArrayList<>();
}
  
public List<InputEvent> processInputEventForCompatibility(InputEvent e) {
    // 小于M并且是motion事件则进行兼容处理
    if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) {
        mProcessedEvents.clear();
        MotionEvent motion = (MotionEvent) e;
        final int mask =
                MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY;
        final int buttonState = motion.getButtonState();
        final int compatButtonState = (buttonState & mask) >> 4;
        if (compatButtonState != 0) {
            motion.setButtonState(buttonState | compatButtonState);
        }
        mProcessedEvents.add(motion);
        return mProcessedEvents;
    }
    return null;
}
转变事件类型并加入队列#

此方法主要是将 InputEvent 转变为 QueuedInputEvent 并将其放到链表的末尾,然后调用 doProcessInputEvents 方法进行处理

void enqueueInputEvent(InputEvent event,
        InputEventReceiver receiver, int flags, boolean processImmediately) {
    // 转变为QueuedInputEvent
    QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
  
    // 将事件插入到链表的末尾
    QueuedInputEvent last = mPendingInputEventTail;
    if (last == null) {
        mPendingInputEventHead = q;
        mPendingInputEventTail = q;
    } else {
        last.mNext = q;
        mPendingInputEventTail = q;
    }
    mPendingInputEventCount += 1;
    Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
            mPendingInputEventCount);
  
    if (processImmediately) {
        // 调用doProcessInputEvents继续处理
        doProcessInputEvents();
    } else {
        scheduleProcessInputEvents();
    }
}
循环事件链并进行分发#

此方法中会遍历整个事件链表,对每个事件调用 deliverInputEvent 方法进行分发

void doProcessInputEvents() {
    // 遍历整个链表,对事件进行分发
    while (mPendingInputEventHead != null) {
        QueuedInputEvent q = mPendingInputEventHead;
        mPendingInputEventHead = q.mNext;
        if (mPendingInputEventHead == null) {
            mPendingInputEventTail = null;
        }
        q.mNext = null;
        // 省略若干行
        // 分发事件
        deliverInputEvent(q);
    }
}
将事件分发到 InputStage#

此方法中会根据 flag 获取 InputStage,然后调用 InputStage 的 deliver 方法分发事件。这里的 InputStage 后面会介绍到,它主要是用来将事件的处理分成多个阶段进行。

private void deliverInputEvent(QueuedInputEvent q) {
    // 省略若干行
    try {
        // 省略若干行
        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
            // flag包含FLAG_UNHANDLED会走这里
            stage = mSyntheticInputStage;
        } else {
            // 是否跳过输入法窗口进行分发
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }
        // 省略若干行
        if (stage != null) {
            // 处理窗口焦点变更
            handleWindowFocusChanged();
            // 分发事件
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

InputStage#

InputStage 主要是用来将事件的处理分成若干个阶段(stage)进行,事件依次经过每一个 stage,如果该事件没有被处理(标识为 FLAG_FINISHED),则该 stage 就会调用 onProcess 方法处理,然后调用 forward 执行下一个 stage 的处理;如果该事件被标识为处理则直接调用 forward,执行下一个 stage 的处理,直到没有下一个 stage(也就是最后一个 SyntheticInputStage)。这里一共有 7 中 stage,各个 stage 间串联起来,形成一个链表,各个 stage 的处理过程大致如下图所示:

webp-1720679655803-177

先来看下这些 stage 是如何串起来的,所有的 Stage 都继承于 InputStage,而 InputStage 是抽象类,它的定义如下:

abstract class InputStage {
    private final InputStage mNext;
    /**
        * Creates an input stage.
        * @param next The next stage to which events should be forwarded.
        */
    public InputStage(InputStage next) {
        // 从构成函数的定义能够看到,传入的next会赋值给当前实例的next,
        // 因此,先插入的就会是最后一个节点(头插法),最终会形成一个链表
        mNext = next;
    }
}

在 ViewRootImpl 的 setView 方法中有以下代码段:

// 如下创建出来的7个实例会串在一起形成一个链表,
// 链表的头是最后创建出来的nativePreImeStage,
// 链表的尾是首先构造出来的mSyntheticInputStage
// Set up the input pipeline.
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
        "aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
// 输入法对应的stage
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
        "aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
        "aq:native-pre-ime:" + counterSuffix);
// 第一个处理事件的stage为NativePreImeInputStage
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
分发传递事件#

该方法中会通过 flag 判断事件是否已经处理,若已经处理则向前调用下一个 stage 处理事件(next 的 deliver 方法),否则会调用 onProcess 来处理事件(此方法需要子类实现),然后会根据处理的结果判断是否需要调用链表中的下一个 stage 来继续处理。

public final void deliver(QueuedInputEvent q) {
    if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
        // 调用next的deliver方法继续分发处理
        forward(q);
    } else if (shouldDropInputEvent(q)) {
        finish(q, false);
    } else {
        traceEvent(q, Trace.TRACE_TAG_VIEW);
        final int result;
        try {
            // 自身处理事件
            result = onProcess(q);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        // 判断是否需要继续分发处理
        apply(q, result);
    }
}
处理 input 事件#

这里我们以 ViewPostImeInputStage 为例 (此 stage 会将事件传递到视图层)介绍事件的分发过程,在 onProcess 方法中根据 event 的类型调用不同的方法进行分发。

@Override
protected int onProcess(QueuedInputEvent q) {
    if (q.mEvent instanceof KeyEvent) {
        // 处理key事件
        return processKeyEvent(q);
    } else {
        final int source = q.mEvent.getSource();
        if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
            // 处理pointer事件
            return processPointerEvent(q);
        } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
            // 处理轨迹球事件
            return processTrackballEvent(q);
        } else {
            // 处理一般的motion事件
            return processGenericMotionEvent(q);
        }
    }
}
处理 key 事件#

此方法中会调用 view 的 dispatchKeyEvent 方法来将 input 事件分发到 view 树上,然后按照 view 的事件分发机制继续分发处理事件,需要注意的是这里的 mView 是 decorview 实例,在 ViewRootImpl 的 setView 方法中被设置。

private int processKeyEvent(QueuedInputEvent q) {
    final KeyEvent event = (KeyEvent)q.mEvent;
    // 省略若干行
    // 调用view的dispatchKeyEvent来分发事件,此处的mView是decorview
    if (mView.dispatchKeyEvent(event)) {
        return FINISH_HANDLED;
    }
    // 省略若干行
    // 继续调用链表的下一个stage来处理
    return FORWARD;
}

DecorView 处理事件#

mView 在 ViewRootImpl 的 setView 方法中被赋值,被赋值的对象便是 DecorView 的实例,而在 ViewPostImeInputStage 的 onPressess 方法中会将 key 事件通过 dispatchKeyEvent 方法传递到 DecorView 中。

dispatchKeyEvent#

此方法中先获取 Window.Callback 对象,然后调用其 dispatchKeyEvent 继续处理,若 callback 为 null 则调用父类同名方法来处理。最后,还会回调 window 的 onKeyDown 和 onKeyUp 方法,需要注意的是 Activity 和 Dialog 都默认实现了 Window.Callback 接口的方法,所以这里就会将事件传递到 Activity 或者 Dialog 里。

public boolean dispatchKeyEvent(KeyEvent event) {
    // 省略若干行
    if (!mWindow.isDestroyed()) {
        // window没有销毁,如何存在Window.Callback,
        // 则调用callback的dispatchKeyEvent继续处理
        // 否则调用父类的dispatchKeyEvent来处理
        final Window.Callback cb = mWindow.getCallback();
        final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
                : super.dispatchKeyEvent(event);
        if (handled) {
            return true;
        }
    }
  
    // 这里回调window的onKeyDown和onKeyUp方法
    return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event)
            : mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
}

Window.Callback(Activity)分发事件#

以 Activity 来介绍事件的传递流程,查看 Activity 的 dispatchKeyEvent 方法。

dispatchKeyEvent#
public boolean dispatchKeyEvent(KeyEvent event) {
    // 省略若干行
    // 调用Window的superDispatchKeyEvent方法继续处理
    Window win = getWindow();
    if (win.superDispatchKeyEvent(event)) {
        return true;
    }
    View decor = mDecor;
    if (decor == null) decor = win.getDecorView();
    // 此处调用KeyEvent的dispatch,传入的receiver为当前实例,
    // 其内部会根据event的action来调用当前实例的onKeyDown和onKeyUp方法
    return event.dispatch(this, decor != null
            ? decor.getKeyDispatcherState() : null, this);
}

PhoneWindow 中处理事件#

Activity 中 getWindow 返回的其实是 PhoneWindow 的实例,看一下 PhoneWindow 的方法实现。

superDispatchKeyEvent#

此方法中会直接调用 mDecor 的同名方法,这个 mDecor 是 DecorView 的实例。

public boolean superDispatchKeyEvent(KeyEvent event) {
    // 调用DecorView的同名方法
    return mDecor.superDispatchKeyEvent(event);
}

DecorView 继续分发事件到 View 树#

这里 Activity 通过调用 DecorView 的 superDispatchKeyEvent 方法,又将事件传入到 DecorView 里了,这里和前面事件传递到 DecorView 的不同之处是前面传递到 dispatchKeyEvent,而这里是 superDispatchKeyEvent。

superDispatchKeyEvent#

此方法中会直接调用 DecorView 的父类的 dispatchKeyEvent 方法,如果事件没有被处理掉的话,就会通过 ViewRootImpl 将其作为 UnhandledEvent 进行处理。

public boolean superDispatchKeyEvent(KeyEvent event) {
    // 省略若干行
    // 这里直接调用父类的dispatchKeyEvent方法,DecorView的父类是FrameLayout,
    // 所以就分发到ViewGroup了,接下来就按照View树的形式从根View向子View分发
    if (super.dispatchKeyEvent(event)) {
        return true;
    }
    // 如果没有被消费掉,则通过ViewRootImpl将其作为Unhandled继续处理
    return (getViewRootImpl() != null) && getViewRootImpl().dispatchUnhandledKeyEvent(event);
}

webp-1720680021901-180

Native 层传递过程#

Input 输入处理流程 Native

InputEventReceiver 的事件来源于哪里#

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 层传递。

webp-1720680518292-186

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。

webp-1720680669663-189

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

webp-1720680863560-192

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

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

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 方法来分发事件。

webp-1720681277193-195

在 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 方法,从而将事件分发出去。

webp-1720681492182-198

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 是如何创建以及进行事件的获取的呢?

webp-1720681684481-201

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 如何获取输入事件#

我们继续看 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;
}
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。