Based on Android 10.

0. InputChannel

InputChannel 是分发 input 事件的通道,driver 产生 input 事件,发送到 system_server 后通过 socket 发送到 app 进程。

每次创建 window 时会创建一对 InputChannel 对象,一个存到 app 进程的 ViewRootImpl 的 mInputChannel 变量,一个存到 system_server 的 WindowState 的 mInputChannel 字段。

1. Open and register input channel

1.1 Open a pair of input channels

1.1.1 WindowState#openInputChannel()

ViewRootImpl 类的 setView() 方法中会创建 InputChannel 对象作为 outInputChannel。然后在 WindowManagerService 类的 addWindow() 方法中调用 WindowState 类的 openInputChannel() 方法打开 server 端和 client 端的 InputChannel。

它实际调用 InputChannel 的静态方法 openInputChannelPair() 创建 InputChanel 对,它又调用 native 方法 nativeOpenInputChannelPair()。Server 端 InputChannel 存在 WindowState 的 mInputChannel 变量,Client 端 InputChanenl 调用 transforTo() 方法传给 ViewRootImpl 的 mInputChannel。

// frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void openInputChannel(InputChannel outInputChannel) {
    if (mInputChannel != null) {
        throw new IllegalStateException("Window already has an input channel.");
    }
    String name = getName();
    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
    mInputChannel = inputChannels[0];
    mClientChannel = inputChannels[1];
    mInputWindowHandle.token = mClient.asBinder();
    if (outInputChannel != null) {
        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.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder());
}

1.1.2 InputChannel#openInputChannelPair()

openInputChannelPair() 最终调用的是 nativeOpenInputChannelPair() 方法。代码注释说明,创建两个 InputChannel 后,一个提供给 InputDispatcher,即 server 端,用于分发 input 事件,另一个提供给应用的 input 队列用于消费 input 事件。

// frameworks/base/core/java/android/view/InputChannel.java
/**
 * Creates a new input channel pair.  One channel should be provided to the input
 * dispatcher and the other to the application's input queue.
 * @param name The descriptive (non-unique) name of the channel pair.
 * @return A pair of input channels.  The first channel is designated as the
 * server channel and should be used to publish input events.  The second channel
 * is designated as the client channel and should be used to consume input events.
 */
public static InputChannel[] openInputChannelPair(String name) {
    if (name == null) {
        throw new IllegalArgumentException("name must not be null");
    }
    return nativeOpenInputChannelPair(name);
}

android_view_InputChannel_nativeOpenInputChannelPair() 函数中调用 InputChannel::openInputChannelPair() 创建两个 InputChannel 对象,然后再封装成 Java 层的 InputChannel 返回。

// frameworks/base/core/jni/android_view_InputChannel.cpp
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;
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
    ...
    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(serverChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(clientChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

1.1.3 InputChannel::openInputChannelPair()

InputChannel.openInputChannelPair() 函数定义在 InputTransport.cpp 中。函数中调用 Linux 的 socketpair() 函数创建一对已连接的 socket,可以把这一对 socket 当成 pipe 返回的文件描述符使用,并且这两个文件描述符都是可读可写的,参考「Linux 上实现双向进程间通信管道」。然后封装成 InputChannel 对象。

// frameworks/native/libs/input/InputTransport.cpp
status_t InputChannel::openInputChannelPair(const String8& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        ...
        return result;
    }

    int bufferSize = SOCKET_BUFFER_SIZE;
    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

    std::string serverChannelName = name;
    serverChannelName.append(" (server)");
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    std::string clientChannelName = name;
    clientChannelName.append(" (client)");
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

InputChannel::InputChannel(const std::string& name, int fd) :
        mName(name) {
    setFd(fd);
}