Android输入系统流程介

2023-05-16


Android输入系统的工作原理概括来说,就是监控/dev/input/下的所有设备节点,当某个节点有数据可读时,将数据读出并进行一系列的翻译加工,然后在所有的窗口中寻找合适的事件接收者,并派发给它。

以Nexus4为例,其/dev/input/下有evnet0~5六个输入设备的节点。它们都是什么输入设备呢?用户的一次输入操作会产生什么样的事件数据呢?获取答案的最简单的办法就是是用getevent与sendevent工具。

  getevent与sendevent工具

Android系统提供了getevent与sendevent两个工具供开发者从设备节点中直接读取输入事件或写入输入事件。

getevent监听输入设备节点的内容,当输入事件被写入到节点中时,getevent会将其读出并打印在屏幕上。由于getevent不会对事件数据做任何加工,因此其输出的内容是由内核提供的最原始的事件。其用法如下:

adb shell getevent [-选项] [device_path]

其中device_path是可选参数,用以指明需要监听的设备节点路径。如果省略此参数,则监听所有设备节点的事件。

打开模拟器,执行adb shell getevent –t(-t参数表示打印事件的时间戳),并按一下电源键(不要松手),可以得到以下一条输出,输出的部分数值会因机型的不同而有所差异,但格式一致:

[   1262.443489] /dev/input/event0: 0001 0074 00000001

松开电源键时,又会产生以下一条输出:

[   1262.557130] /dev/input/event0: 0001 0074 00000000

这两条输出便是按下和抬起电源键时由内核生成的原始事件。注意其输出是十六进制的。每条数据有五项信息:产生事件时的时间戳([   1262.443489]),产生事件的设备节点(/dev/input/event0),事件类型(0001),事件代码(0074)以及事件的值(00000001)。其中时间戳、类型、代码、值便是原始事件的四项基本元素。除时间戳外,其他三项元素的实际意义依照设备类型及厂商的不同而有所区别。在本例中,类型0x01表示此事件为一条按键事件,代码0x74表示电源键的扫描码,值0x01表示按下,0x00则表示抬起。这两条原始数据被输入系统包装成两个KeyEvent对象,作为两个按键事件派发给Framework中感兴趣的模块或应用程序。

注意一条原始事件所包含的信息量是比较有限的。而在Android API中所使用的某些输入事件,如触摸屏点击/滑动,包含了很多的信息,如XY坐标,触摸点索引等,其实是输入系统整合了多个原始事件后的结果。这个过程将在5.2.4节中详细探讨。

为了对原始事件有一个感性的认识,读者可以在运行getevent的过程中尝试一下其他的输入操作,观察一下每种输入所对应的设备节点及四项元素的取值。

输入设备的节点不仅在用户空间可读,而且是可写的,因此可以将将原始事件写入到节点中,从而实现模拟用户输入的功能。sendevent工具的作用正是如此。其用法如下:

sendevent <节点路径> <类型><代码> <值>

可以看出,sendevent的输入参数与getevent的输出是对应的,只不过sendevent的参数为十进制。电源键的代码0x74的十进制为116,因此可以通过快速执行如下两条命令实现点击电源键的效果:

adb shell sendevent /dev/input/event0 1 116 1 #按下电源键

adb shell sendevent /dev/input/event0 1 116 0 #抬起电源键

执行完这两条命令后,可以看到设备进入了休眠或被唤醒,与按下实际的电源键的效果一模一样。另外,执行这两条命令的时间间隔便是用户按住电源键所保持的时间,所以如果执行第一条命令后迟迟不执行第二条,则会产生长按电源键的效果——关机对话框出现了。很有趣不是么?输入设备节点在用户空间可读可写的特性为自动化测试提供了一条高效的途径。[1]

现在,读者对输入设备节点以及原始事件有了直观的认识,接下来看一下Android输入系统的基本原理。

还有个命令补充一下:

ADB输入键值:input keyevent xx 这个可以模拟一个android的键值。排查问题的时候比较有用,可以判定第linux层按键获取和转换派发的问题还是android层面的问题。
26表示POWER;3表示BACK,24音量加,25音量减

  Android输入系统简介

上一节讲述了输入事件的源头是位于/dev/input/下的设备节点,而输入系统的终点是由WMS管理的某个窗口。最初的输入事件为内核生成的原始事件,而最终交付给窗口的则是KeyEvent或MotionEvent对象。因此Android输入系统的主要工作是读取设备节点中的原始事件,将其加工封装,然后派发给一个特定的窗口以及窗口中的控件。这个过程由InputManagerService(以下简称IMS)系统服务为核心的多个参与者共同完成。

输入系统的总体流程和参与者如图5-1所示。


图 5-1 输入系统的总体流程与参与者

图5-1描述了输入事件的处理流程以及输入系统中最基本的参与者。它们是:

·  Linux内核,接受输入设备的中断,并将原始事件的数据写入到设备节点中。

·  设备节点,作为内核与IMS的桥梁,它将原始事件的数据暴露给用户空间,以便IMS可以从中读取事件。

·  InputManagerService,一个Android系统服务,它分为Java层和Native层两部分。Java层负责与WMS的通信。而Native层则是InputReader和InputDispatcher两个输入系统关键组件的运行容器。

·  EventHub,直接访问所有的设备节点。并且正如其名字所描述的,它通过一个名为getEvents()的函数将所有输入系统相关的待处理的底层事件返回给使用者。这些事件包括原始输入事件、设备节点的增删等。

·  InputReader,I是IMS中的关键组件之一。它运行于一个独立的线程中,负责管理输入设备的列表与配置,以及进行输入事件的加工处理。它通过其线程循环不断地通过getEvents()函数从EventHub中将事件取出并进行处理。对于设备节点的增删事件,它会更新输入设备列表于配置。对于原始输入事件,InputReader对其进行翻译、组装、封装为包含了更多信息、更具可读性的输入事件,然后交给InputDispatcher进行派发。

·  InputReaderPolicy,它为InputReader的事件加工处理提供一些策略配置,例如键盘布局信息等。

·  InputDispatcher,是IMS中的另一个关键组件。它也运行于一个独立的线程中。InputDispatcher中保管了来自WMS的所有窗口的信息,其收到来自InputReader的输入事件后,会在其保管的窗口中寻找合适的窗口,并将事件派发给此窗口。

·  InputDispatcherPolicy,它为InputDispatcher的派发过程提供策略控制。例如截取某些特定的输入事件用作特殊用途,或者阻止将某些事件派发给目标窗口。一个典型的例子就是HOME键被InputDispatcherPolicy截取到PhoneWindowManager中进行处理,并阻止窗口收到HOME键按下的事件。

·  WMS,虽说不是输入系统中的一员,但是它却对InputDispatcher的正常工作起到了至关重要的作用。当新建窗口时,WMS为新窗口和IMS创建了事件传递所用的通道。另外,WMS还将所有窗口的信息,包括窗口的可点击区域,焦点窗口等信息,实时地更新到IMS的InputDispatcher中,使得InputDispatcher可以正确地将事件派发到指定的窗口。

·  ViewRootImpl,对于某些窗口,如壁纸窗口、SurfaceView的窗口来说,窗口即是输入事件派发的终点。而对于其他的如Activity、对话框等使用了Android控件系统的窗口来说,输入事件的终点是控件(View)。ViewRootImpl将窗口所接收到的输入事件沿着控件树将事件派发给感兴趣的控件。

简单来说,内核将原始事件写入到设备节点中,InputReader不断地通过EventHub将原始事件取出来并翻译加工成Android输入事件,然后交给InputDispatcher。InputDispatcher根据WMS提供的窗口信息将事件交给合适的窗口。窗口的ViewRootImpl对象再沿着控件树将事件派发给感兴趣的控件。控件对其收到的事件作出响应,更新自己的画面、执行特定的动作。所有这些参与者以IMS为核心,构建了Android庞大而复杂的输入体系。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android输入系统流程介 的相关文章

随机推荐

  • HTTPS-自签证书macOS必须使用thisisunsafe

    HTTPS是站点部署的发展趋势 xff0c 由于HTTP的一系列安全问题 例如网络嗅探时数据报文默认是明文传输 xff0c 容易遭受MitM攻击篡改数据等等 什么是MITM 中间人攻击 xff1f 在内网环境部署站点的时候 xff0c HT
  • Linux-SMTP中继服务器搭建

    本文介绍使用Linux搭建SMTP服务器 xff0c 通过搭配DNS记录修改达到SPF认证的目的 本文参考 xff1a SMTP搭建教程 硬件要求 CPU span class token punctuation span 2C4T 主存
  • Swift5-引入SnapKit

    适用于因网络情况 xff0c 按照SnapKit官方手册引入失败或下载过慢的情况 请先核对Xcode和Swift版本 Xcode Version span class token operator span Version span cla
  • Vue3-减少应用部署打包体积的N种方式【持续更新】

    Vue3默认支持OptionsAPI和Composition API 混编的方式进行开发 xff0c 如果在新系统建设过程中完全抛弃了OptionsAPI方式 xff0c 可以使用vite定义全局变量来告诉Vue关闭对OptionsAPI的
  • Golang-简单-找不同

    题 xff1a 给定两个字符串 s 和 t xff0c 它们只包含小写字母 字符串 t 由字符串 s 随机重排 xff0c 然后在随机位置添加一个字母 请找出在 t 中被添加的字母 示例 1 xff1a 输入 xff1a s 61 abcd
  • Golang-简单-判断子序列

    题 xff1a 给定字符串 s 和 t xff0c 判断 s 是否为 t 的子序列 字符串的一个子序列是原始字符串删除一些 xff08 也可以不删除 xff09 字符而不改变剩余字符相对位置形成的新字符串 xff08 例如 xff0c 34
  • Android NDK开发基础

    文章目录 cmake语法基础cmake添加日志 xff1a cmake增加宏字符串比较cmake在build gradle中传递编译参数到cmake 通过javah生成native对应的c 43 43 头文件jni和java之间字符串的相互
  • iOS 使用科大讯飞技术实现语音转文字(语音听写)

    本文主要介绍的是利用科大讯飞技术实现语音转文字的功能 语音听写 首先 注册讯飞账号 xff0c 申请APPID 然后 下载科大讯飞SDK将开发工具包中lib目录下的iflyMSC framework添加到新建工程中 按下图添加 SDK 所需
  • Pycharm的汉化方法(pycharm改为中文版)

    很多开始接触python的朋友都会用到一款工具 xff1a pycharm xff0c 但默认是英文版的不知从何下手 xff0c 本文介绍两种不同的pycharm汉化方法 xff0c 将其变为中文版的界面 xff08 对于windows电脑
  • ubuntu14.04服务器版本搭建OpenStack+附上资源链接(稳成功的那种)

    ubuntu14 04服务器版本搭建OpenStack 43 附上资源链接 xff08 稳成功的那种 xff09 一 想必大家在搭建过程中 xff0c 遇见了很多的困难是吗 xff1f 没事 xff0c 今天小编就带你搭建属于你自己的Ope
  • 部署taokeeper

    环境 span class hljs title wget span https mirrors tuna tsinghua edu cn apache tomcat tomcat span class hljs number 7 span
  • 字符串排序(C语言实现)

    习题8 7 字符串排序 xff08 C语言实现 xff09 方法一 xff1a 选择排序 span class token macro property span class token directive keyword include
  • DVWA简介

    DVWA部署完成后通过默认账号密码 xff08 admin password xff09 进入欢迎界面 xff08 Home页面 xff09 xff0c 欢迎页面对DVWA平台做了简单的介绍 xff0c 如果需要对DVWA平台有一个更加深入
  • ios 导航控制器(navigationController)代码方式创建

    NavigationCOntroller 使用 BooL application UIApplication application didFinishLaunchingWithOptions NSDictionary launchOpti
  • ansible 简介和基本安装

    目录 ansible 简介和基本安装 自动化运维 运维的自动化发展历程运维工程师的职能划分自动化运维的应用场景企业实际应用场景分析 Dev开发环境测试环境发布环境生产环境 灰度环境 生产环境的一部分 常用的自动化运维工具ansible基本介
  • 使用OpenCV进行摄像机标定

    Cv照相机定标和三维重建 目录 隐藏 1 针孔相机模型和变形 2 照相机定标 2 1 ProjectPoints2 2 2 FindHomography 2 3 CalibrateCamera2 2 4 FindExtrinsicCamer
  • distributor之Interrupt Set-Enable Registers, GICD_ISENABLERn

    相对于distributor基地址偏移区间在0x100 0x17C 此寄存器就是把对应的中断使能 xff0c 使之可以被触发上报处理器 xff1b 此寄存器是写0无效的 xff0c 所以在写此寄存器时可以直接写 xff0c 不用再先读再或再
  • pip怎么安装到用户目录(不需要管理员权限),怎样安装指定python版本的包

    1 pip怎么安装到用户目录 xff08 不需要管理员权限 xff09 在用户的Home目录底下有个 pip目录 xff0c 即 pip xff0c 在这里面新建一个pip conf xff0c 里面写上 install install o
  • 时间机器测试

    这创意实在太搞 xff0c 不得不转载 xff1a 1 准备一张厚厚的 xff0c 防水的 xff0c 质量好的纸 xff0c 至少要100克的 xff0c 但表面不能太光滑 xff0c 防止墨迹脱落 2 在纸上用郑重的语气写上 xff0c
  • Android输入系统流程介

    Android输入系统的工作原理概括来说 xff0c 就是监控 dev input 下的所有设备节点 xff0c 当某个节点有数据可读时 xff0c 将数据读出并进行一系列的翻译加工 xff0c 然后在所有的窗口中寻找合适的事件接收者 xf