inputChannel是客户端窗口与inputDiapatcher传递的通道。本篇文章主要分析InputChannel的建立过程。
从addView开始说起, 会调用到viewRootImpl的setVew
ViewRootImpl
1221 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
1222 int userId) {
1223 synchronized (this) {
InputChannel inputChannel = null;
1316 if ((mWindowAttributes.inputFeatures
1317 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
1318 inputChannel = new InputChannel();
1319 }
1340 res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
1341 getHostVisibility(), mDisplay.getDisplayId(), userId,
1342 mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
1343 mTempControls, attachedFrame, compatScale);
1449 if (inputChannel != null) {
1450 if (mInputQueueCallback != null) {
1451 mInputQueue = new InputQueue();
1452 mInputQueueCallback.onInputQueueCreated(mInputQueue);
1453 }
1454 mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
1455 Looper.myLooper());
ViewRootImpl.setView函数首先生成一个InputChannel对象
此时的对象是空的
经过addToDisplayAsUser后将InputChannel赋值
最后把生成一个mInputEventReceiver 用来接收input事件
1. InputChannel初始化
frameworks/base/core/java/android/view/InputChannel.java
7 @UnsupportedAppUsage
78 public InputChannel() {
79 }
2.通过addToDisplayAsUser传递给WindowManagerService赋值
WindowManagerService.java
1430
1431 public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
1432 int displayId, int requestUserId, @InsetsType int requestedVisibleTypes,
1433 InputChannel outInputChannel, InsetsState outInsetsState,
1434 InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
1435 float[] outSizeCompatScale) {
1665 final boolean openInputChannels = (outInputChannel != null
1666 && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
1667 if (openInputChannels) {
1668 win.openInputChannel(outInputChannel);
1669 }
调用到windowState的openInputChanel
WindowState.java
2626 void openInputChannel(@NonNull InputChannel outInputChannel) {
2627 if (mInputChannel != null) {
2628 throw new IllegalStateException("Window already has an input channel.");
2629 }
2630 String name = getName();
2631 mInputChannel = mWmService.mInputManager.createInputChannel(name);
2632 mInputChannelToken = mInputChannel.getToken();
2633 mInputWindowHandle.setToken(mInputChannelToken);
2634 mWmService.mInputToWindowMap.put(mInputChannelToken, this);
2635 mInputChannel.copyTo(outInputChannel);
2636 }
InputManagerService.java
168 private final NativeInputManagerService mNative;
776 public InputChannel createInputChannel(String name) {
777 return mNative.createInputChannel(name);
778 }
3235 public InputChannel createInputChannel(String inputChannelName) {
3236 return InputManagerService.this.createInputChannel(inputChannelName);
3237 }
NativeInputManagerService.java
291 @Override
292 public native InputChannel createInputChannel(String name);
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
1771 static jobject nativeCreateInputChannel(JNIEnv* env, jobject nativeImplObj, jstring nameObj) {
1772 NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
1773
1774 ScopedUtfChars nameChars(env, nameObj);
1775 std::string name = nameChars.c_str();
1776
1777 base::Result<std::unique_ptr<InputChannel>> inputChannel = im->createInputChannel(name);
1778
1779 if (!inputChannel.ok()) {
1780 std::string message = inputChannel.error().message();
1781 message += StringPrintf(" Status=%d", static_cast<int>(inputChannel.error().code()));
1782 jniThrowRuntimeException(env, message.c_str());
1783 return nullptr;
1784 }
1785
1786 jobject inputChannelObj =
1787 android_view_InputChannel_createJavaObject(env, std::move(*inputChannel));
1788 if (!inputChannelObj) {
1789 return nullptr;
1790 }
1791
1792 android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
1793 handleInputChannelDisposed, im);
1794 return inputChannelObj;
1795 }
535 base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputChannel(
536 const std::string& name) {
537 ATRACE_CALL();
538 return mInputManager->getDispatcher().createInputChannel(name);
539 }
1.创建了一堆Channel, 为 serverChannel; 和clientChannel;调用openInputChannelPair将两个inputChannel赋值
2. 创建了一个connection 对象
将服务端的token和connection 作为key和value放入mConnectionsByToken中, 这里的token是新建的一个IBinder对象作为connection的唯一的标识符
获得serverChannel的文件描述符,把该文件描述符通过调用mLooper.addFd添加到lopper的文件描述符列表中去。
3. 生成一个LooperEventCallback,回调触发的时候调用InputDispatcher::handleReceiveCallback
这样的话native环境的looper类就可以监控该管道的文件描述符, 当该管道收到数据时, 就会收到一个通知,就会触发LooperEventCallback的handleEvent回调,那么最终会调用InputDispatcher::handleReceiveCallback。
/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
270 std::unordered_map<sp<IBinder>, std::shared_ptr<Connection>, StrongPointerHash<IBinder>>
271 mConnectionsByToken GUARDED_BY(mLock);
5809 Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
5810 if (DEBUG_CHANNEL_CREATION) {
5811 ALOGD("channel '%s' ~ createInputChannel", name.c_str());
5812 }
5813
5814 std::unique_ptr<InputChannel> serverChannel;
5815 std::unique_ptr<InputChannel> clientChannel;
5816 status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
5817
5818 if (result) {
5819 return base::Error(result) << "Failed to open input channel pair with name " << name;
5820 }
5821
5822 { // acquire lock
5823 std::scoped_lock _l(mLock);
5824 const sp<IBinder>& token = serverChannel->getConnectionToken();
5825 int fd = serverChannel->getFd();
5826 std::shared_ptr<Connection> connection =
5827 std::make_shared<Connection>(std::move(serverChannel), /*monitor=*/false,
5828 mIdGenerator);
5829
5830 if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) {
5831 ALOGE("Created a new connection, but the token %p is already known", token.get());
5832 }
5833 mConnectionsByToken.emplace(token, connection);
5834
5835 std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
5836 this, std::placeholders::_1, token);
5837
5838 mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback),
5839 nullptr);
5840 } // release lock
5841
5842 // Wake the looper because some connections have changed.
5843 mLooper->wake();
5844 return clientChannel;
5845 }
/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
407 status_t openInputChannelPair(const std::string& name, std::shared_ptr<InputChannel>& serverChannel,
408 std::unique_ptr<InputChannel>& clientChannel) {
409 std::unique_ptr<InputChannel> uniqueServerChannel;
410 status_t result = InputChannel::openInputChannelPair(name, uniqueServerChannel, clientChannel);
411
412 serverChannel = std::move(uniqueServerChannel);
413 return result;
414 }
/frameworks/native/libs/input/InputTransport.cpp
390 status_t InputChannel::openInputChannelPair(const std::string& name,
391 std::unique_ptr<InputChannel>& outServerChannel,
392 std::unique_ptr<InputChannel>& outClientChannel) {
393 int sockets[2];
394 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
395 status_t result = -errno;
396 ALOGE("channel '%s' ~ Could not create socket pair. errno=%s(%d)", name.c_str(),
397 strerror(errno), errno);
398 outServerChannel.reset();
399 outClientChannel.reset();
400 return result;
401 }
402
403 int bufferSize = SOCKET_BUFFER_SIZE;
404 setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
405 setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
406 setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
407 setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
408
409 sp<IBinder> token = new BBinder();
410
411 std::string serverChannelName = name + " (server)";
412 android::base::unique_fd serverFd(sockets[0]);
413 outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);
414
415 std::string clientChannelName = name + " (client)";
416 android::base::unique_fd clientFd(sockets[1]);
417 outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
418 return OK;
419 }
ative层创建完服务端和客户端InputChannel后,最终会返回客户端InputChannel,接着JNI层的InputManagerService基于该C++层InputChannel对象生成了一个Java层的InputChannel对象,最终返回到了WindowState#openInputChannel处。
WindowState.java
2626 void openInputChannel(@NonNull InputChannel outInputChannel) {
2627 if (mInputChannel != null) {
2628 throw new IllegalStateException("Window already has an input channel.");
2629 }
2630 String name = getName();
2631 mInputChannel = mWmService.mInputManager.createInputChannel(name);
2632 mInputChannelToken = mInputChannel.getToken();
2633 mInputWindowHandle.setToken(mInputChannelToken);
2634 mWmService.mInputToWindowMap.put(mInputChannelToken, this);
2635 mInputChannel.copyTo(outInputChannel);
2636 }
1. 首先拿到token赋值给mInputChannelToken, 这样WindowState中就有了与native一致的token
然后吧这个token放入inputWindowHandle中, InputWindowHandlel记录了窗口的信息
最后把token作为key, windowState作为value放入WMS的mInputToWindowMap, 这样WindowManagerService便可以根据从Native层传来的token对象获取到对应的WIndowState对象。
然后把inputChannel赋值给 outInputChannel最终传递给客服端ViewRootImpl中
3. 生成一个mInputEventReceiver
客服端拿到InputChannel 后根据此值生成一个mInputEventReceiver
回到ViewRootImpl
ViewRootImpl.java
1449 if (inputChannel != null) {
1450 if (mInputQueueCallback != null) {
1451 mInputQueue = new InputQueue();
1452 mInputQueueCallback.onInputQueueCreated(mInputQueue);
1453 }
1454 mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
1455 Looper.myLooper());
WindowInputEventReceiver是一个内部类
ViewRootImpl.java
9310 final class WindowInputEventReceiver extends InputEventReceiver {
9311 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
9312 super(inputChannel, looper);
9313 }
9314
调用父类的构造函数
/frameworks/base/core/java/android/view/InputEventReceiver.java
69 public InputEventReceiver(InputChannel inputChannel, Looper looper) {
70 if (inputChannel == null) {
71 throw new IllegalArgumentException("inputChannel must not be null");
72 }
73 if (looper == null) {
74 throw new IllegalArgumentException("looper must not be null");
75 }
76
77 mInputChannel = inputChannel;
78 mMessageQueue = looper.getQueue();
79 mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
80 mInputChannel, mMessageQueue);
81
82 mCloseGuard.open("InputEventReceiver.dispose");
83 }
frameworks/base/core/jni/android_view_InputEventReceiver.cpp
497 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
498 jobject inputChannelObj, jobject messageQueueObj) {
499 std::shared_ptr<InputChannel> inputChannel =
500 android_view_InputChannel_getInputChannel(env, inputChannelObj);
501 if (inputChannel == nullptr) {
502 jniThrowRuntimeException(env, "InputChannel is not initialized.");
503 return 0;
504 }
505
506 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
507 if (messageQueue == nullptr) {
508 jniThrowRuntimeException(env, "MessageQueue is not initialized.");
509 return 0;
510 }
511
512 sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
513 receiverWeak, inputChannel, messageQueue);
514 status_t status = receiver->initialize();
515 if (status) {
516 std::string message = android::base::
517 StringPrintf("Failed to initialize input event receiver. status=%s(%d)",
518 statusToString(status).c_str(), status);
519 jniThrowRuntimeException(env, message.c_str());
520 return 0;
521 }
522
523 receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
524 return reinterpret_cast<jlong>(receiver.get());
525 }
/frameworks/base/core/jni/android_view_InputEventReceiver.cpp
124 NativeInputEventReceiver::NativeInputEventReceiver(
125 JNIEnv* env, jobject receiverWeak, const std::shared_ptr<InputChannel>& inputChannel,
126 const sp<MessageQueue>& messageQueue)
127 : mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
128 mInputConsumer(inputChannel),
129 mMessageQueue(messageQueue),
130 mBatchedInputEventPending(false),
131 mFdEvents(0) {
132 if (kDebugDispatchCycle) {
133 ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName().c_str());
134 }
135 }
142 status_t NativeInputEventReceiver::initialize() {
143 setFdEvents(ALOOPER_EVENT_INPUT);
144 return OK;
145 }
146
184 void NativeInputEventReceiver::setFdEvents(int events) {
185 if (mFdEvents != events) {
186 mFdEvents = events;
187 int fd = mInputConsumer.getChannel()->getFd();
188 if (events) {
189 mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr);
190 } else {
191 mMessageQueue->getLooper()->removeFd(fd);
192 }
193 }
194 }
调用当前NativeInputEventReceiver的Looper的addFd函数监听客户端InputChannel对应的socket 的文件描述符,并且在有数据到来时执行相应回调,这里看到回调参数传入的是this。因为NativeInputEventReceiver是继承LooperCallback的:
那么一旦向服务端InputChannel保存的socket写入数据,则客户端这边的注册的NativeInputEventReceiver则触发handleEvent回调
总结
1. 在ViewRootImpl时new了inputChannel对象, 通过WMS的addWindow调用WindowState的openChannel,然后调用生成了一个native的inputChannel对象,channel对象的生成, 首先new了一个IBinder对象,然后生成了包含服务端和客服端, 根据服务端的channel生成了一个connection对象, 此对象是InputDispatcher操作的基本单位,最后把inputChannel转化为java的inputChanel对象, 赋值给WindowState的变量, 最后把token和window赋值给WMS的map,然后返回给ViewRootImpl对象
2. 生成的InputChannel对象作为变为生成WindowInputReceier对象, 调用native的初始化,添加到native的文件描述符中, 这样当有数据改变时候就可以回调handleEvent