Android14 InputManager-InputChanel的建立

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

  • 19
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值