Android 源码 输入系统之 InputChannel 通信通道建立

626 阅读7分钟

上一节完成了焦点窗口关联,现在可以分析如何将输入事件继续从 InputDispatcher 继续分发。InputChannel 的 sendMessage 将消息发送出去。实际是调用 socket 的 send 接口来发送消息的。具体一点其实使用的是 socketpair。所以我们先来学习 Linux 如何使用 socketpair,然后“破解” InputChannel 通信,最后再去分析输入事件窗口分发。

一、socketpair 使用

用于创建一对无名的、相互连接的套接字。

#include <sys/types.h> 
#include <sys/socket.h>

int socketpair(int domain, int type, int protocol, int sv[2]);

参数

domain: 协议家族

type: 套接字类型

protocol: 协议类型

sv: 返回套接字对

返回值

成功返回 0,失败返回 -1

UNIX 域套接字用于在同一台计算机上运行的进程之间的通信。虽然因特网域套接字可用于 同一目的,但 UNIX 域套接字的效率更高。UNIX 域套接字仅仅复制数据,它们并不执行协议处理,不需要添加或删除网络报头,无需计算校验和,不要产生顺序号,无需发送确认报文。

UNIX 域套接字提供流和数据报两种接口。UNIX 域数据报服务是可靠的,既不会丢失报文也不会传递出错。UNIX 域套接字就像是套接字和管道的混合。可以使用它们面向网络的域套接字接口或者使用 socketpair 函数來创建一对无命名的、相互连接的 UNIX 域套接字。

虽然接口足够通用,允许 socketpair 用于其他域,但一般来说操作系统仅对 UNIX 域提供支持。

下面是一个例程,父进程和子进程相互发送消息。父进程调用 sleep 休息 1 秒是为了子进程有机会执行。

#include <sys/types.h>
#include <sys/socket.h>

#include <stdlib.h>
#include <stdio.h>

int main () {
    int fd[2];

    int r = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
    if (r < 0) {
        perror("socketpair()");
        exit(1);
    }

    if (fork()) {
        /* Parent process: echo client */
        int val = 0;
        close(fd[1]);
        while (1) {
            sleep(1);
            ++val;
            printf("Parent process Sending data: %d\n", val);
            write(fd[0], &val, sizeof(val));
            read(fd[0], &val, sizeof(val));
            printf("Parent process Data received: %d\n", val);
        }
    } else {
        /* Child process: echo server */
        int val;
        close(fd[0]);
        while (1) {
            read(fd[1], &val, sizeof(val));
            printf("Child process Data received: %d\n", val);
            ++val;
            printf("Child process Sending data: %d\n", val);
            write(fd[1], &val, sizeof(val));
        }
    }
}

运行结果

Parent process Sending data: 1
Child process Data received: 1
Child process Sending data: 2
Parent process Data received: 2
Parent process Sending data: 3
Child process Data received: 3
Child process Sending data: 4
Parent process Data received: 4
Parent process Sending data: 5
Child process Data received: 5
Child process Sending data: 6
Parent process Data received: 6
Parent process Sending data: 7
Child process Data received: 7
Child process Sending data: 8
Parent process Data received: 8
Parent process Sending data: 9
Child process Data received: 9
Child process Sending data: 10
Parent process Data received: 10
Parent process Sending data: 11
Child process Data received: 11
Child process Sending data: 12
Parent process Data received: 12
Parent process Sending data: 13
Child process Data received: 13
Child process Sending data: 14
Parent process Data received: 14
Parent process Sending data: 15
Child process Data received: 15
Child process Sending data: 16
Parent process Data received: 16
......

二、InputChannel 通信

回顾《Android 源码 输入系统之窗口关联》一节,InputChannel 通信得从 ViewRootImpl 类 setView 继续分析。

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
    ......
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                ......
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    // 创建客户端 InputChannel 对象
                    mInputChannel = new InputChannel();
                }
                try {
                    ......
                    // Binder 机制调用 Session 对象 addToDisplay 方法,注意入参包括 InputChannel 对象
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                    ......
                } finally {
                    ......
                }
                ......
                if (mInputChannel != null) {
                    if (mInputQueueCallback != null) {
                        // 创建 InputQueue 对象
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
                    // 接收输入事件,创建 WindowInputEventReceiver 对象
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());
                }
                ......
            }
        }
    }
    ......
}

输入通道(InputChannel)指定用于将输入事件发送到另一个进程中的窗口的文件描述符。它是可打包的,因此可以将其发送到接收事件的进程。每次只应该有一个线程从 InputChannel 中读取数据。

frameworks/base/core/java/android/view/InputChannel.java

public final class InputChannel implements Parcelable {
    ......
    // 创建一个未初始化的输入通道。
    // 它可以通过从一个 Parcel 读取数据或将另一个输入通道的状态传输到这个输入通道来初始化。
    public InputChannel() {
    }
    ......
}

Session 类 addToDisplay 方法实际工作由 WindowManagerService 类 addWindow 方法完成。

frameworks/base/services/core/java/com/android/server/wm/Session.java

final class Session extends IWindowSession.Stub
        implements IBinder.DeathRecipient {
    final WindowManagerService mService;
    ......
    @Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
            Rect outOutsets, InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outStableInsets, outOutsets, outInputChannel);
    }
    ......
}
  1. 创建 InputChannel 对
  2. 将服务端 InputChannel 赋给服务端的 WindowState
  3. 将客户端 InputChannel 传递到 outInputChannel, 最终返回客户端应用进程
  4. 将服务端 InputChannel 注册到 InputDispatcher

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    ......
    final InputMonitor mInputMonitor = new InputMonitor(this);
    ......
    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
        ......
        synchronized(mWindowMap) {
            ......
            // WindowState 代表窗口管理器中的窗口。
            WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
            ......
            if (outInputChannel != null && (attrs.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                String name = win.makeInputChannelName();
                // 创建 InputChannel 对
                InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
                // 将服务端 InputChannel 赋给服务端的 WindowState
                win.setInputChannel(inputChannels[0]);
                // 将客户端 InputChannel 传递到 outInputChannel, 最终返回客户端应用进程
                inputChannels[1].transferTo(outInputChannel);
                // 将服务端 InputChannel 注册到 InputDispatcher 
                mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
            }
            ......
        }
        ......
    }
    ......
}

创建 InputChannel 对,实际是使用 socketpair 来完成的。openInputChannelPair 简单做了 name 判空后,实际工作由 nativeOpenInputChannelPair 方法完成。

frameworks/base/core/java/android/view/InputChannel.java

public final class InputChannel implements Parcelable {
    ......
    private static native InputChannel[] nativeOpenInputChannelPair(String name);
    ......
    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 + "'");
        }
        return nativeOpenInputChannelPair(name);
    }

    ......
}

不难看出 nativeOpenInputChannelPair 只是一个 jni 接口,实际工作由 jni native 层对应函数(android_view_InputChannel_nativeOpenInputChannelPair)完成。

  1. name 转化(从 java String 对象转化为 C++ String8)
  2. 调用 Native InputChannel 对象 openInputChannelPair 方法
  3. 构建 NativeInputChannel 对象,并将 NativeInputChannel 对象转化为 Java InputChannel 对象返回

注意 Native InputChannel 对象和 NativeInputChannel 对象,前者为 C++ 类 InputChannel,后者为 C++ 类 NativeInputChannel。

frameworks/base/core/jni/android_view_InputChannel.cpp

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
    String8 name(nameChars);
    env->ReleaseStringUTFChars(nameObj, nameChars);

    sp<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

    if (result) {
        String8 message;
        message.appendFormat("Could not open input channel pair.  status=%d", result);
        jniThrowRuntimeException(env, message.string());
        return NULL;
    }

    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            new NativeInputChannel(serverChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            new NativeInputChannel(clientChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}
  1. 调用 socketpair 创建一对无名的、相互连接的套接字
  2. setsockopt() 函数,用于任意类型、任意状态套接口的设置选项值

SO_RCVBUF int 为接收确定缓冲区大小。
SO_RCVBUF int 为接收确定缓冲区大小。

  1. 分别创建服务端和客户端 Native 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)) {
        status_t result = -errno;
        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
                name.string(), errno);
        outServerChannel.clear();
        outClientChannel.clear();
        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));

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

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

NativeInputChannel 对象将传递来的 InputChannel 指针保存在自己的成员变量 mInputChannel 中。

frameworks/base/core/jni/android_view_InputChannel.cpp

NativeInputChannel::NativeInputChannel(const sp<InputChannel>& inputChannel) :
    mInputChannel(inputChannel), mDisposeCallback(NULL) {
}

再来分析 android_view_InputChannel_createInputChannel 函数。

  1. 调用 jni 方法 NewObject 创建一个 Java InputChannel 对象
  2. 调用 android_view_InputChannel_setNativeInputChannel 将 nativeInputChannel 对象指针强转为 jlong,然后将其设置到 Java InputChannel 类 mPtr 成员上。

frameworks/base/core/jni/android_view_InputChannel.cpp

static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
        NativeInputChannel* nativeInputChannel) {
    jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
            gInputChannelClassInfo.ctor);
    if (inputChannelObj) {
        android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
    }
    return inputChannelObj;
}

InputChannel 类 transferTo 函数,将 InputChannel 内部状态的所有权转移到另一个实例,并使该实例无效。这用于在 binder 调用中将输入通道作为 out 参数传递。

frameworks/base/core/java/android/view/InputChannel.java

public final class InputChannel implements Parcelable {
    ......
    public void transferTo(InputChannel outParameter) {
        if (outParameter == null) {
            throw new IllegalArgumentException("outParameter must not be null");
        }

        nativeTransferTo(outParameter);
    }
    ......
}

otherObj 即对应的入参,调用 android_view_InputChannel_getNativeInputChannel 方法可将 Java InputChannel 对象的 mPtr 成员变量强转为 NativeInputChannel 对象,由于传递过来的 Java InputChannel 对象是个“空壳”,所以强转以后一定为空,否则抛出异常。

接下来调用 android_view_InputChannel_getNativeInputChannel 将 obj 转化为 NativeInputChannel 对象。并将其(实际是指针)设置到 otherObj mPtr 成员变量上。

最后将 obj mPtr 成员变量设置为 0,即表示 NativeInputChannel 对象为 NULL。

frameworks/base/core/jni/android_view_InputChannel.cpp

static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
        jobject otherObj) {
    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
                "Other object already has a native input channel.");
        return;
    }

    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, obj);
    android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
    android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}

下面是 android_view_InputChannel_getNativeInputChannel 和 android_view_InputChannel_setNativeInputChannel 函数,主要调用 jni 方法 GetLongField 和 SetLongField,实现 Native 层操作 java 对象成员变量。

frameworks/base/core/jni/android_view_InputChannel.cpp

static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
        jobject inputChannelObj) {
    jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
    return reinterpret_cast<NativeInputChannel*>(longPtr);
}

static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,
        NativeInputChannel* nativeInputChannel) {
    env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
             reinterpret_cast<jlong>(nativeInputChannel));
}

回到 WindowManagerService addWindow 方法,继续分析将服务端 InputChannel 注册到 InputDispatcher 的过程。registerInputChannel 函数实际调用了 nativeRegisterInputChannel 完成注册。

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

public class InputManagerService extends IInputManager.Stub
        implements Watchdog.Monitor {
    ......
    private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
            InputWindowHandle inputWindowHandle, boolean monitor);
    ......
    public void registerInputChannel(InputChannel inputChannel,
            InputWindowHandle inputWindowHandle) {
        if (inputChannel == null) {
            throw new IllegalArgumentException("inputChannel must not be null.");
        }

        nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
    }
    ......
}
  1. 将 ptr 强转为 NativeInputManager 对象
  2. 将 inputChannelObj jobject 转化为 Native InputChannel 对象
  3. 将 inputWindowHandleObj jobject 转化为 Native InputWindowHandle 对象
  4. 调用 NativeInputManager 类 registerInputChannel 方法完成实际注册工作

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == NULL) {
        throwInputChannelNotInitialized(env);
        return;
    }

    sp<InputWindowHandle> inputWindowHandle =
            android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);

    status_t status = im->registerInputChannel(
            env, inputChannel, inputWindowHandle, monitor);
    if (status) {
        String8 message;
        message.appendFormat("Failed to register input channel.  status=%d", status);
        jniThrowRuntimeException(env, message.string());
        return;
    }
    ......
}

NativeInputManager 类 registerInputChannel 方法最终调用 InputDispatcher 类的 registerInputChannel 完成真正的注册。

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
        const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    return mInputManager->getDispatcher()->registerInputChannel(
            inputChannel, inputWindowHandle, monitor);
}
  1. 检查 InputChannel 是否已经注册过
  2. 创建 Connection 对象,他表示客户端和服务端的一个输入数据通道
  3. 以 fd 为 key 将 Connection 添加到容器(mConnectionsByFd)中
  4. 将 fd 添加到 Looper 监听列表中。一旦对端的 Socket 写入数据,Looper 就会被唤醒,接着就会调用 handleReceiveCallback

frameworks/native/services/inputflinger/InputDispatcher.cpp

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    ......
    { // acquire lock
        AutoMutex _l(mLock);
        // 进入此 case 表示 inputChannel 已经注册过了
        if (getConnectionIndexLocked(inputChannel) >= 0) {
            ALOGW("Attempted to register already registered input channel '%s'",
                    inputChannel->getName().string());
            return BAD_VALUE;
        }
        // Connection 表示客户端和服务端的一个输入数据通道
        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
        // 获取 socketpair fd
        int fd = inputChannel->getFd();
        // 以 fd 为 key 将 Connection 添加到容器中
        mConnectionsByFd.add(fd, connection);
        ......
        // 将 fd 添加到 Looper 监听列表中,一旦对端的 socket 写入数据,Looper 就会被唤醒
        // 接着就会调用 handleReceiveCallback
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

    // 唤醒 Looper,因为一些连接(Connection)已经改变
    mLooper->wake();
    return OK;
}

代码走到这里,InputDispatcher 就和 InputChannel 建立了关联。现在是时候回到 ViewRootImpl setView 方法中具体分析如何关联客户端 InputChannel。马上来分析创建 WindowInputEventReceiver 对象流程。

在 WindowInputEventReceiver 构造器中调用了 InputEventReceiver 构造器。

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
    ......
    final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }

        @Override
        public void onInputEvent(InputEvent event) {
            enqueueInputEvent(event, this, 0, true);
        }

        @Override
        public void onBatchedInputEventPending() {
            if (mUnbufferedInputDispatch) {
                super.onBatchedInputEventPending();
            } else {
                scheduleConsumeBatchedInput();
            }
        }

        @Override
        public void dispose() {
            unscheduleConsumeBatchedInput();
            super.dispose();
        }
    }
    ......
}

InputEventReceiver 构造器中首先检查入参 inputChannel 和 looper 是否为 null,接着从 looper 中获取 MessageQueue (mMessageQueue),最后调用 nativeInit 进一步初始化。

frameworks/base/core/java/android/view/InputEventReceiver.java

public abstract class InputEventReceiver {
    ......
    public InputEventReceiver(InputChannel inputChannel, Looper looper) {
        if (inputChannel == null) {
            throw new IllegalArgumentException("inputChannel must not be null");
        }
        if (looper == null) {
            throw new IllegalArgumentException("looper must not be null");
        }

        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                inputChannel, mMessageQueue);

        mCloseGuard.open("dispose");
    }
    ......
}
  1. 转化 Java InputChannel 对象为 Native InputChannel 对象
  2. 转化 Java MessageQueue 对象为 Native MessageQueue 对象
  3. 构建 NativeInputEventReceiver 对象
  4. 调用 NativeInputEventReceiver 对象 initialize() 方法初始化

frameworks/base/core/jni/android_view_InputEventReceiver.cpp

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == NULL) {
        jniThrowRuntimeException(env, "InputChannel is not initialized.");
        return 0;
    }

    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    status_t status = receiver->initialize();
    if (status) {
        String8 message;
        message.appendFormat("Failed to initialize input event receiver.  status=%d", status);
        jniThrowRuntimeException(env, message.string());
        return 0;
    }

    receiver->incStrong(gInputEventReceiverClassInfo.clazz); // 保留对象的引用
    return reinterpret_cast<jlong>(receiver.get());
}

NativeInputEventReceiver 构造函数将传递来的入参保存到对应的成员变量中。

frameworks/base/core/jni/android_view_InputEventReceiver.cpp

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

initialize() 函数仅仅调用了 setFdEvents() 函数,然后直接返回 OK。

frameworks/base/core/jni/android_view_InputEventReceiver.cpp

status_t NativeInputEventReceiver::initialize() {
    setFdEvents(ALOOPER_EVENT_INPUT);
    return OK;
}

由于 mFdEvents 初始化为 0, ALOOPER_EVENT_INPUT = 1 << 0,因此会赋值 mFdEvents = ALOOPER_EVENT_INPUT。然后取出 socket fd,就会向客户端 Looper 添加 fd 描述符,当有数据从服务端写入,就会唤醒 Looper。最终回调 NativeInputEventReceiver 的 handleEvent 方法。

frameworks/base/core/jni/android_view_InputEventReceiver.cpp

void NativeInputEventReceiver::setFdEvents(int events) {
    if (mFdEvents != events) {
        mFdEvents = events;
        int fd = mInputConsumer.getChannel()->getFd();
        if (events) {
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}

老规矩时序图作为最后的总结。
在这里插入图片描述