Android InputChannel连接
InputChannel是InputDispatcher 和应用程序 (InputTarget) 的通讯桥梁,InputDispatcher 通知应用程序有输入事件,通过InputChannel中的socket进行通信。
连接InputDispatcher和窗口
WinodwManagerService:addwindow: WMS 添加窗口时,会创建一对 InputChannel,其中一个保存在 WindowState 中,并注册给 IMS,它是服务端,另一个则通过传出参数 outInputChannel 交给调用者,是客户端
1.服务端连接的建立
addwindow 函数中,有以下三项工作:
通过 WindowState.setInputChannel 函数保存服务端的 InputChannel
通过 IMS.registerInputChannel 将 InputChannel 注册到 IMS
通过 InputMonitor.updateInputWindowsLw 将所有窗口的信息更新到 IMS
2.窗口端连接的建立
当窗口端通过 addwindow 函数获取 InputChannel,便会使用它创建一个 InputEventReceiver 对象,可以接收来自InputChannel 的输入事件,触发 onInputEvent 回调
InputEventRecevier 如何工作?将 InputChannel 的可读事件注册到 Looper,然后在事件到来时从 InputChannel 中读取 InputMessage,并翻译成 InputEvent,然后回调 InputEventReceiver 的 onInputEvent
详细调用栈如下:
@frameworks/base/core/java/android/view/ViewRootImpl.java
setViewinputChannel = new InputChannel();
@frameworks/base/services/core/java/com/android/server/wm/Session.javamWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes, mDisplay.getDisplayId(), userId, inputChannel
@frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java Service.addWindow(this, window, attrs, viewVisibility, displayId, userId, requestedVisibilities, outInputChannel, //WinodwManagerService:addwindow
@frameworks/base/services/core/java/com/android/server/wm/WindowState.javawin.openInputChannel(outInputChannel);
@frameworks/base/services/core/java/com/android/server/input/InputManagerService.java mInputChannel = mWmService.mInputManager.createInputChannel(name);
@frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp nativeCreateInputChannel(mPtr, name);NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);base::Result<std::unique_ptr<InputChannel>> inputChannel = im->createInputChannel(env, name);
@frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp mInputManager->getDispatcher()->createInputChannel(name);
@frameworks/native/libs/input/InputTransport.cppstatus_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)std::string serverChannelName = name + " (server)";outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);std::string clientChannelName = name + " (client)";outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
@frameworks/native/services/inputflinger/dispatcher/Connection.cppsp<Connection> connection = new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);inputChannel(inputChannel),inputPublisher(inputChannel),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);mInputChannel.copyTo(outInputChannel); //复制给outInputChannelif (focusChanged) { displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus, false /*updateInputWindows*/);
@frameworks/base/services/core/java/com/android/server/wm/InputMonitor.javadisplayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);scheduleUpdateInputWindows();mHandler.post(mUpdateInputWindows);run()mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);updateInputFocusRequest(mRecentsAnimationInputConsumer);requestFocus(recentsAnimationInputConsumer.mWindowHandle.token, recentsAnimationInputConsumer.mName);
@frameworks/base/core/java/android/view/SurfaceControl.javamInputTransaction.setFocusedWindow(mInputFocus, windowName, mDisplayId); nativeSetFocusedWindow(mNativeObject, token, windowName, null /* focusedToken */, null /* focusedWindowName */, displayId);
@frameworks/native/libs/gui/SurfaceComposerClient.cpp transaction->setFocusedWindow(request);mInputWindowCommands.focusRequests.push_back(request);
@frameworks/native/services/surfaceflinger/SurfaceFlinger.cppSurfaceFlinger::handleMessageTransactionif (getTransactionFlags(eTransactionFlushNeeded)) { flushTransactionQueues();}applyTransactionState(transaction.states, transaction.displays, transaction.inputWindowCommands,transactionFlags |= addInputWindowCommands(inputWindowCommands);
@frameworks/native/libs/gui/LayerState.cpp bool hasChanges = mInputWindowCommands.merge(inputWindowCommands);focusRequests.insert(focusRequests.end(), std::make_move_iterator(other.focusRequests.begin()),SurfaceFlinger::onMessageInvalidateupdateInputFlinger();
@frameworks/native/services/inputflinger/InputManager.cpp for (const auto& focusRequest : mInputWindowCommands.focusRequests) { mInputFlinger->setFocusedWindow(focusRequest);}mDispatcher->setFocusedWindow(request);
@frameworks/base/core/jni/android_view_SurfaceControl.cpp mInputEventReceiver = new WindowInputEventReceiver(inputChannel, Looper.myLooper());
@frameworks/base/core/java/android/view/InputEventReceiver.javasuper(inputChannel, looper);
@frameworks/base/core/jni/android_view_InputEventReceiver.cppmReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this), inputChannel, mMessageQueue);sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env, receiverWeak, inputChannel, messageQueue);status_t status = receiver->initialize();setFdEvents(ALOOPER_EVENT_INPUT);mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr);// Set up the input pipeline.mSyntheticInputStage = new SyntheticInputStage();InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage, "aq:native-post-ime:" + counterSuffix);InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);InputStage imeStage = new ImeInputStage(earlyPostImeStage, "aq:ime:" + counterSuffix);InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage, "aq:native-pre-ime:" + counterSuffix);mFirstInputStage = nativePreImeStage;mFirstPostImeInputStage = earlyPostImeStage;//InputDispatcher向InputChannel使用socket写入输入事件,触发InputEventReceiver调用来接收输入事件
@frameworks/base/core/jni/android_view_InputEventReceiver.cpp
NativeInputEventReceiver::handleEventNativeInputEventReceiver::consumeEvents(env, false /*consumeBatches*/, -1, nullptr)
@frameworks/native/libs/input/InputTransport.cppmInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent);status_t result = mChannel->receiveMessage(&mMsg);nRead = ::recv(getFd(), msg, sizeof(InputMessage), MSG_DONTWAIT); //从socket中读输入事件case InputMessage::Type::FOCUS: {initializeFocusEvent(focusEvent, &mMsg);case InputMessage::Type::MOTION: {initializeMotionEvent(motionEvent, &mMsg);//构造java的event事件case AINPUT_EVENT_TYPE_FOCUS: { env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.onFocusEvent, jboolean(focusEvent->getHasFocus()), jboolean(focusEvent->getInTouchMode()));
@frameworks/base/core/java/android/view/ViewRootImpl.javaonFocusEventwindowFocusChanged(hasFocus, inTouchMode);msg.what = MSG_WINDOW_FOCUS_CHANGED;mHandler.sendMessage(msg);case MSG_WINDOW_FOCUS_CHANGED: { handleWindowFocusChanged(); } case AINPUT_EVENT_TYPE_MOTION: {inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);if (inputEventObj) { env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
@frameworks/base/core/java/android/view/InputEventReceiver.java dispatchInputEvent
@frameworks/base/core/java/android/view/ViewRootImpl.javaonInputEvent(event);enqueueInputEvent(event, this, 0, true);if (processImmediately) { doProcessInputEvents(); }deliverInputEvent(q); //在deliverInputEvent函数中做输入事件的实际分发stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; //这里开始选择 责任链的入口,具体请看InputStage的处理流程stage.deliver(q); //这里主要调用InputStage的deliver方法进行分发,InputStage代表了输入事件的处理阶段,使用责任链模式设计模式。result = onProcess(q);NativePreImeInputStage::onProcess
相关文章:
Android InputChannel连接
InputChannel是InputDispatcher 和应用程序 (InputTarget) 的通讯桥梁,InputDispatcher 通知应用程序有输入事件,通过InputChannel中的socket进行通信。 连接InputDispatcher和窗口 WinodwManagerService:addwindow: WMS 添加窗口时,会创建…...

爬虫笔记17——selenium框架的使用
selenium框架的使用 1、python程序安装selenium框架2、下载Chrome谷歌驱动3、selenium的基本使用4、多个标签页切换顺序混乱的问题 1、python程序安装selenium框架 # 在安装过程中最好限定框架版本为4.9.1 # pip install selenium 没有制定版本,非镜像下载也会比较…...

[BUUCTF从零单排] Web方向 02.Web入门篇之『常见的搜集』解题思路(dirsearch工具详解)
这是作者新开的一个专栏《BUUCTF从零单排》,旨在从零学习CTF知识,方便更多初学者了解各种类型的安全题目,后续分享一定程度会对不同类型的题目进行总结,并结合CTF书籍和真实案例实践,希望对您有所帮助。当然࿰…...

深度相机识别物体——实现数据集准备与数据集分割
一、数据集准备——Labelimg进行标定 1.安装labelimg——pip install labelimg -i https://pypi.tuna.tsinghua.edu.cn/simple 2.建立相应的数据集存放文件夹 3.打开labelimg,直接在命令行输入labelimg即可,并初始化 4.开始标注,设置标注好…...

STM32第十一课:ADC采集光照
文章目录 需求一、ADC概要二、实现流程1.开时钟,分频,配IO2.配置ADC工作模式3.配置通道4.复位校准5.数值的获取 三、需求的实现总结 需求 通过ADC转换实现光照亮度的数字化测量,最后将实时测量的结果打印在串口上。 一、ADC概要 ADC全称是A…...

python查找支撑数 青少年编程电子学会python编程等级考试三级真题解析2022年3月
目录 python查找支撑数 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python查找支撑数 2022年3月 python编程等级考试级编程题 一、题目要求…...
创建一个快速、高效的网络爬虫:PHP和Selenium示例
随着互联网的不断发展,数据爬取已经成为了许多人的必备技能。而网络爬虫则是实现数据爬取的重要工具之一。 网络爬虫可以自动化地访问网站、获取内容、分析页面并提取所需数据。其中,Selenium是一款非常优秀的网络自动化测试工具,能够模拟真…...

两张图片怎样拼在一起?将两张图片拼在一起的几种方法介绍
两张图片怎样拼在一起?拼接两张图片是一种常见的编辑技巧,能够将不同的视觉元素融合成一个整体,从而创造出更加生动和丰富的图像效果。无论是为了设计创意作品、制作社交媒体内容,还是简单地为个人相册增添趣味,掌握如…...
百日筑基第五天-关于maven
百日筑基第五天-关于maven Maven 是什么 Maven 是一个项目管理工具,它包含了一个项目对象模型(Project Object Model),反映在配置中,就是一个 pom.xml 文件。是一组标准集合,一个项目的生命周期、一个依赖…...

【CSS in Depth 2 精译】2.2 em 和 rem + 2.2.1 使用 em 定义字号
当前内容所在位置 第一章 层叠、优先级与继承第二章 相对单位 2.1 相对单位的威力 2.1.1 响应式设计的兴起 2.2 em 与 rem ✔️ 2.2.1 使用 em 定义字号 ✔️2.2.2 使用 rem 设置字号 2.3 告别像素思维2.4 视口的相对单位2.5 无单位的数值与行高2.6 自定义属性2.7 本章小结 2.…...
C++Primer Plus 第十四章代码重用:14.4.4 数组模板示例和非类型参数
系列文章目录 14.4.4 数组模板示例和非类型参数 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录14.4.4 数组模板示例和非类型参数 14.4.4 数组模板示例和非类型参数 模板常用作容器类,这…...

短视频哪个软件好用?成都柏煜文化传媒有限公司
短视频哪个软件好用?一文带你了解各大平台特色 随着移动互联网的飞速发展,短视频已经成为现代人生活中不可或缺的一部分。市面上涌现出众多短视频平台,它们各具特色,满足了不同用户的需求。那么,短视频哪个软件好用呢…...

金融科技:重塑用户体验,驱动满意度飙升
随着科技的飞速发展,金融科技(FinTech)已经深入到我们生活的每一个角落,从日常支付到投资理财,再到跨境汇款,它都在悄无声息地改变着我们的金融行为。而在这背后一个不可忽视的驱动力就是金融科技对用户体验…...
JavaScript——算术运算符
目录 任务描述 相关知识 - * / %运算符 递增运算符和递减运算符 编程要求 任务描述 本关任务:给定两个字符串变量,把它们转为数字后相除,拼接被除数、除数和余数为一个新的字符串。 例如:a 为 "5",b 为…...

备份SQL Server数据库并还原到另一台服务器
我可以将SQL Server数据库备份到另一台服务器吗? 有时您可能希望将 SQL数据库从一台服务器复制到另一台服务器,或者将计算机复制到计算机。可能的场景包括测试、检查一致性、从崩溃的机器恢复数据库、在不同的机器上处理同一个项目等。 是的,…...

二刷算法训练营Day45 | 动态规划(7/17)
目录 详细布置: 1. 139. 单词拆分 2. 多重背包理论基础 3. 背包总结 3.1 背包递推公式 3.2 遍历顺序 01背包 完全背包 详细布置: 1. 139. 单词拆分 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单…...

大模型项目落地时,该如何估算模型所需GPU算力资源
近期公司有大模型项目落地。在前期沟通时,对于算力估算和采购方案许多小伙伴不太了解,在此对相关的算力估算和选择进行一些总结。 不喜欢过程的可以直接 跳到HF上提供的模型计算器 要估算大模型的所需的显卡算力,首先要了解大模型的参数基础知识。 大模型的规模、参数的理解…...

LLM应用开发-RAG系统评估与优化
前言 Hello,大家好,我是GISer Liu😁,一名热爱AI技术的GIS开发者,在上一篇文章中,我们学习了如何基于LangChain构建RAG应用,并且通过Streamlit将这个RAG应用部署到了阿里云服务器;&am…...

秋招突击——第七弹——Redis快速入门
文章目录 引言Redis是什么 正文对象String字符串面试重点 List面试考点 压缩列表ZipList面试题 Set面试题讲解 Hash面试重点 HASHTABLE底层面试考点 跳表面试重点 ZSET有序链表面试重点 总结 引言 在项目和redis之间,我犹豫了一下,觉得还是了解学习一下…...

软考初级网络管理员__操作系统单选题
1.在Windows资源管理器中,假设已经选定文件,以下关于“复制”操作的叙述中,正确的有()。 按住Ctr键,拖至不同驱动器的图标上 按住AIt键,拖至不同驱动器的图标上 直接拖至不同驱动器的图标上 按住Shift键࿰…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...