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键࿰…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
C++实现分布式网络通信框架RPC(2)——rpc发布端
有了上篇文章的项目的基本知识的了解,现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...
TJCTF 2025
还以为是天津的。这个比较容易,虽然绕了点弯,可还是把CP AK了,不过我会的别人也会,还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...
负载均衡器》》LVS、Nginx、HAproxy 区别
虚拟主机 先4,后7...
路由基础-路由表
本篇将会向读者介绍路由的基本概念。 前言 在一个典型的数据通信网络中,往往存在多个不同的IP网段,数据在不同的IP网段之间交互是需要借助三层设备的,这些设备具备路由能力,能够实现数据的跨网段转发。 路由是数据通信网络中最基…...
