news 2026/10/8 6:57:45

12、窗口注册与InputChannel:WindowManagerService如何注册窗口,InputChannel的创建与配对

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
12、窗口注册与InputChannel:WindowManagerService如何注册窗口,InputChannel的创建与配对

12.1 窗口注册的起点:addWindow

应用要显示窗口,第一步就是调用WMS的addWindow方法。这个方法在WMS里大概有300多行,逻辑非常密集。我们挑重点看。

当应用通过Binder调用到WMS时,WMS会做几件事:

  • 检查窗口的权限、token是否合法
  • 创建WindowState对象,代表这个窗口
  • 分配Surface(这块我们后面会细讲)
  • 创建InputChannel

你看,创建InputChannel是窗口注册的必经之路。没有它,事件就传不过去。

核心流程:

应用进程 → Binder调用 → WMS.addWindow() → 创建WindowState → 创建InputChannel → 返回给应用

我在项目中遇到过一个问题:某个第三方应用窗口注册成功了,但死活收不到触摸事件。查了半天,发现是InputChannel创建时出错了,但WMS没有抛异常,只是静默失败了。这种坑,真的让人头大。

12.2 InputChannel的创建与配对

好,我们来看InputChannel到底是怎么创建的。这部分代码在WMS.addWindow里,大概长这样:

// WindowManagerService.java InputChannel inputChannel = null; if (outInputChannel != null) { String name = win.makeInputChannelName(); InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); win.setInputChannel(inputChannels[0]); inputChannel = inputChannels[1]; // 把服务端的那一端注册到InputManagerService mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle); }

这里有个关键函数——openInputChannelPair。它返回的是一个数组,里面有两个InputChannel。为什么是两个?

你想想看,事件传递是双向的吗?其实不是。事件是从WMS流向应用,但应用处理完事件后,需要反馈一个“处理完成”的信号。所以,这两个InputChannel实际上是一对SocketPair。

索引用途所在进程
inputChannels[0]服务端(WMS侧)system_server
inputChannels[1]客户端(应用侧)应用进程

说白了,openInputChannelPair底层就是调用了Linux的socketpair系统调用。创建了一对互相连接的Unix域套接字。一个写,另一个就能读,反之亦然。

我的经验:

我曾经调试过一个性能问题,发现事件从WMS到应用进程延迟很高。后来用strace抓了一下,发现socketpair的缓冲区大小是默认的。我们手动调大了SO_SNDBUF和SO_RCVBUF,延迟就降下来了。这种底层细节,文档里基本不会写,得自己踩坑才知道。

12.3 注册到InputManagerService

InputChannel创建好之后,WMS会把服务端的那一端(inputChannels[0])注册到InputManagerService。这一步很重要。

注册的代码在InputManagerService.java里:

// InputManagerService.java public void registerInputChannel(InputChannel inputChannel, InputWindowHandle inputWindowHandle) { nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle); }

这个nativeRegisterInputChannel会走到Native层,最终调用到InputDispatcher的registerInputChannel方法。InputDispatcher会把InputChannel和对应的窗口信息存到一个HashMap里。

为什么要存起来?因为InputDispatcher在分发事件时,需要根据焦点窗口找到对应的InputChannel,然后往里面写数据。

注意:

InputChannel注册到InputDispatcher后,InputDispatcher会创建一个Connection对象。这个Connection会监听InputChannel的可读事件。一旦应用进程处理完事件并写回信号,Connection就会收到通知。如果应用进程挂掉了,这个Connection也会检测到,InputDispatcher就会把该窗口标记为“死亡”。

12.4 应用进程接收InputChannel

那应用进程是怎么拿到InputChannel的呢?还记得addWindow方法的最后一个参数outInputChannel吗?它是一个Binder对象,WMS会把inputChannels[1]通过这个Binder传回给应用进程。

应用进程的ViewRootImpl会收到这个InputChannel,然后把它包装成一个WindowInputEventReceiver。这个Receiver会创建一个InputEventReceiver的Native对象,开始监听InputChannel上的事件。

流程大概是:

  1. 应用调用WindowManagerGlobal.addView
  2. 内部调用WMS.addWindow,传入一个空的InputChannel
  3. WMS创建一对InputChannel,把服务端注册到IMS,客户端通过Binder返回
  4. 应用拿到客户端的InputChannel,开始监听事件

嗯,这里有个细节。你可能觉得InputChannel的传递是同步的,其实不是。WMS在返回addWindow结果时,InputChannel就已经通过Binder传回来了。但应用进程真正开始监听,是在ViewRootImpl.setView方法里。这中间有一个时间窗口。

我曾经遇到过一个bug:快速启动和关闭窗口时,事件会丢失。原因就是窗口已经销毁了,但InputChannel还没来得及注销,InputDispatcher还在往里面写数据。后来我们在窗口销毁时增加了同步等待,确保InputChannel注销完成才返回。

12.5 小结

好了,这一章的内容就这些。我们来理一下思路:

  • 窗口注册的核心是addWindow方法
  • InputChannel通过socketpair创建,是一对互相连接的管道
  • 服务端注册到InputDispatcher,客户端传给应用进程
  • InputDispatcher通过InputChannel把事件写入应用进程
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 6:56:50

把 GEO / AI 落地工作台拆成五层:工具能解决什么、不能解决什么、什么时候才需要私有化部署

先说结论:工具只是工作台,不是结果制造机。 选型之前,先把一条完整链路拆开看——哪些层可以用工具提效、哪些层必须由人判断、哪些层一旦涉及内部系统和客户数据就要单独评估权限与边界。 顺序反了,最常见的结局是:工…

作者头像 李华
网站建设 2026/10/8 6:56:36

5款AI写论文哪个好?拆开论文写作的“流水线”看工具分工|云智变AI官网www.yunzhibian.cn|微信公众号搜一搜 云智变ai学术

你搜“5款AI写论文哪个好”,大概率会看到一堆横向测评,把ChatGPT、DeepSeek、Kimi、豆包、Gemini放在同一张表里比谁生成的段落更流畅。 这个比法本身就错了。因为它们根本不在同一条流水线上。 一篇毕业论文的写作,实际上包含四道工序&…

作者头像 李华
网站建设 2026/10/8 6:56:02

大模型微调核心技术详解:LoRA与QLoRA原理、实战、差异及选型指南

摘要:随着大语言模型参数规模突破百亿、千亿级,传统全参数微调显存开销大、算力成本高、过拟合风险显著等问题愈发突出。参数高效微调(PEFT)技术成为工业界落地大模型定制的主流方案,其中 LoRA(低秩自适应微…

作者头像 李华
网站建设 2026/10/8 6:54:33

微信AI支付又变了

大家好,我是小悟。 微信支付官宣,AI专属卡又多了两个“新搭子”:Hermes Agent和腾讯云Lighthouse Agent。 微信支付的AI专属卡,并不是一个“新出的付款方式”那么简单。它更像是一个专门给AI智能体用的“零钱包”,独立…

作者头像 李华