Android事件分发的事件由来原理分析

Andriod事件分发的事件从何而来

上一篇最后留下了一个疑问,WMS的事件是哪里来的?

注册事件回调是通过mWindowSession.addToDisplayAsUser来实现的,这是一个Binder调用实际调用的是frameworks/base/services/core/java/com/android/server/wm/Session.java这个类。

//frameworks/base/services/core/java/com/android/server/wm/Session.java 
 @Override
 public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
 int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
 InputChannel outInputChannel, InsetsState outInsetsState,
 InsetsSourceControl[] outActiveControls, Rect outAttachedFrame,
 float[] outSizeCompatScale) {
 return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
 requestedVisibilities, outInputChannel, outInsetsState, outActiveControls,
 outAttachedFrame, outSizeCompatScale);
 }
​

这里的mService就是WMS.调用的就是WMS的addWindow,addWindow方法很长,其中与事件相关的就两行

//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
...... 
 final WindowState win = new WindowState(this, session, client, token, parentWindow,appOp[0], attrs, viewVisibility, session.mUid, userId,session.mCanAddInternalSystemWindow);
 win.openInputChannel(outInputChannel);
//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();
 mInputChannel = mWmService.mInputManager.createInputChannel(name);
 mInputChannelToken = mInputChannel.getToken();
 mInputWindowHandle.setToken(mInputChannelToken);
 mWmService.mInputToWindowMap.put(mInputChannelToken, this);
 if (outInputChannel != null) {
 //将native创建的InputChannel复制给参数outInputChannel
 mInputChannel.copyTo(outInputChannel);
 } else {
 // If the window died visible, we setup a fake input channel, so that taps
 // can still detected by input monitor channel, and we can relaunch the app.
 // Create fake event receiver that simply reports all events as handled.
 mDeadWindowEventReceiver = new DeadWindowEventReceiver(mInputChannel);
 }
 }

调用WMS中的成员mInputManager

调用了WMS中的成员mInputManager来注册了InputChannel,mInputManager是一个InputManagerService。

这下就对了,事件从InputManagerService中来很合理。

public InputChannel createInputChannel(String name) {
 return mNative.createInputChannel(name);
 }

调用的mNative的方法

这个对象是在InputManagerService创建的时候初始化的

public InputManagerService(Context context) {
 this(new Injector(context, DisplayThread.get().getLooper()));
 }
​
 @VisibleForTesting
 InputManagerService(Injector injector) {
 // The static association map is accessed by both java and native code, so it must be
 // initialized before initializing the native service.
 mStaticAssociations = loadStaticInputPortAssociations();
​
 mContext = injector.getContext();
 mHandler = new InputManagerHandler(injector.getLooper());
 mNative = injector.getNativeService(this);
 ....
 }
//frameworks/base/services/core/java/com/android/server/input/NativeInputManagerService.java
 NativeInputManagerService getNativeService(InputManagerService service) {
 return new NativeInputManagerService.NativeImpl(service, mContext, mLooper.getQueue());
 }
​

最终返回的是一个NativeImpl实例。字面意思就知道了,这是一个Native方法的实现,createInputChannel来到了native层。

//frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputChannel(
 const std::string& name) {
 ATRACE_CALL();
 return mInputManager->getDispatcher().createInputChannel(name);
}

调用了mInputManager的getDispatcher函数看名字就知道应该有个变量mDispatcher,查看mInputManager是怎么创建的可以发现是在NativeInputManager创建的时候初始化的

InputManager* im = new InputManager(this, this);
 mInputManager = im;

看看InputManager怎么初始化

InputManager::InputManager(
 const sp<InputReaderPolicyInterface>& readerPolicy,
 const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
 mDispatcher = createInputDispatcher(dispatcherPolicy);
 mClassifier = std::make_unique<InputClassifier>(*mDispatcher);
 mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
 mReader = createInputReader(readerPolicy, *mBlocker);
}

这里就出现了重要的两个类InputDispatcherInputReader,createInputChanne方法l最终调用到了InputDispatcher中的createInputChannel。

//frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
 if (DEBUG_CHANNEL_CREATION) {
 ALOGD("channel '%s' ~ createInputChannel", name.c_str());
 }
 std::unique_ptr<InputChannel> serverChannel;
 std::unique_ptr<InputChannel> clientChannel;
 	//调用创建了一个serverChannel和一个clientChannel
 status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
 if (result) {
 return base::Error(result) << "Failed to open input channel pair with name " << name;
 }
 { // acquire lock
 std::scoped_lock _l(mLock);
 const sp<IBinder>& token = serverChannel->getConnectionToken();
 int fd = serverChannel->getFd();
 sp<Connection> connection =
 new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);
 if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) {
 ALOGE("Created a new connection, but the token %p is already known", token.get());
 }
 mConnectionsByToken.emplace(token, connection);
 std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
 this, std::placeholders::_1, token);
 mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
 } // release lock
 // Wake the looper because some connections have changed.
 mLooper->wake();
 return clientChannel;
}

createInputChannel干了3件事

  • 首先使用openInputChannelPair创建了2个InputChannel,一个clientChannel和一个serverChannel
  • 将serverChannel封装成connection,并放入成员变量mConnectionsByToken中管理,这样在事件到来的时候就可以使用connection向客户端发送事件了
  • 利用Looper持续监听serverChannel,事件处理的回调消息会就到InputDispatcher::handleReceiveCallback回调,最后把clientChannel返回给客户端,也就是最初在WMS中得到的InputChannel。

首先看下openInputChannelPair

//frameworks/native/libs/input/InputTransport.cpp
status_t InputChannel::openInputChannelPair(const std::string& name,
 std::unique_ptr<InputChannel>& outServerChannel,
 std::unique_ptr<InputChannel>& outClientChannel) {
 int sockets[2];
 	//真正创建了socket
 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
 status_t result = -errno;
 ALOGE("channel '%s' ~ Could not create socket pair. errno=%s(%d)", name.c_str(),
 strerror(errno), errno);
 outServerChannel.reset();
 outClientChannel.reset();
 return result;
 }
	//设置了socket传输的大小为32k
 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));
 sp<IBinder> token = new BBinder();
 std::string serverChannelName = name + " (server)";
 android::base::unique_fd serverFd(sockets[0]);
 outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);
 std::string clientChannelName = name + " (client)";
 android::base::unique_fd clientFd(sockets[1]);
 outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
 return OK;
}

熟悉Linux的话就知道socketpair创建了一对双向的socket,往socket[0]中写能从socket[1]读,反向也是一样,分别创建了outServerChannel和outClientChannel,两个InputChannel有着同一个BBinder作为token。

回到createInputChannel中

const sp<IBinder>& token = serverChannel->getConnectionToken();
 int fd = serverChannel->getFd();//拿到socket fd
 sp<Connection> connection =
 new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);
 if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) {
 ALOGE("Created a new connection, but the token %p is already known", token.get());
 }
 mConnectionsByToken.emplace(token, connection);
 std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
 this, std::placeholders::_1, token);
 mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);

这里将创建的serverChannel封装成了connection,同时用token作为key,存到了mConnectionsByToken中,这样就可以利用token来快速找到serverChannel封装的connection。最后监听serverChannel的fd,有事件时回调给InputDispatcher::handleReceiveCallback方法的最后把创建的clientChannel返回给了客户端,就是开头的WMS中。这样在WMS就也能通过clientChannel来获取事件了。

作者:Arthas0v0

%s 个评论

要回复文章请先登录注册