Based on Android 10.
InputChannel 是分发 input 事件的通道,driver 产生 input 事件,发送到 system_server 后通过 socket 发送到 app 进程。
每次创建 window 时会创建一对 InputChannel 对象,一个存到 app 进程的 ViewRootImpl 的 mInputChannel 变量,一个存到 system_server 的 WindowState 的 mInputChannel 字段。
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());
}
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;
}
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);
}