android输入系统

Paste_Image.png

InputManagerService(IMS)

Linux内核,接受输入设备的中断,并将原始事件的数据写入设备节点中
设备接电,作为内核与IMS的桥梁,将原始事件的数据暴露给用户空间,以便IMS可以从中读取事件
InputManagerService,一个android系统服务,分为Java层和Native层两部分,java层负责与WMS通信,而Native层则是InputReader和InputDispatcher两个输入系统关键组件的运行容器
EventHub,直接访问所有的设备节点,通过一个名为getEvents()的函数将所有输入系统相关的待处理的底层事件返回给使用者,包括原始输入事件,设备节点的增删等
InputReader,是IMS中的关键组件之一,它运行一个独立的线程中,负责管理输入设备的列表和配置,以及进行输入事件的加工处理,它通过其线程循环不断地通过getEvents()函数从EventHub中将事件取出并进行处理,对于设备节点的增删事件,它会更新输入设备列表与配置,对于原始输入事件,InputReader对其进行翻译,组装,封装为包含更多信息,更多可读性的输入事件,然后交给InputDispatcher进行派发
InputReaderPolicy,为InputReader的事件加工处理提供一些策略配置
InputDispatcher,是IMS中的另一个关键组件,运行于一个独立的线程中,InputDispatcher中保管来自WMS的所有窗口的信息,收到InputReader的输入事件后,会在其保管的窗口中寻找合适的窗口,并将事件派发给此窗口
InputDispatcherPolicy,为InputDispatcher的派发过程提供策略控制,例如HOME键被InputDispatcherPolicy截取到PhoneWindowManager中处理,并阻止窗口收到HOME键按下的事件
WMS,并不是输入系统的一员,新建窗口时,WMS为新窗口和IMS创建了事件传递所用的通道,会将窗口的可点击区域,焦点窗口等信息实时更新到IMS的InputDispatcher中,使得InputDispatcher可以正确将事件派发到指定窗口
ViewRootImpl,对某些窗口,如壁纸窗口,SurfaceView的窗口来说,窗口就是输入事件派发的终点,而对其他的如Activity,对话框等使用了Android控件系统的窗口来说,输入事件的终点是控件

IMS构成

SystemServer->ServerThread.run()
1.创建新的IMS对象
->com_android_server_input_InputManagerService.cpp->nativeInit()
创建了NativeInputManager对象,该对象实现了InputReaderPolicyInterface与InputDispatcherPolicyInterface接口,创建EventHub和InputManager,InputManager创建了InputReader与InputDispatcher以及InputReaderThread与InputDispatcherThread

2.调用IMS对象的start函数完成启动

![Upload Paste_Image.png failed. Please try again.]

![Upload Paste_Image.png failed. Please try again.]

Paste_Image.png

InputReader的总流程

InputReader.cpp->InputReaderThread::threadLoop()
分三步:
1.首先从EventHub抽取未处理的时间列表,一类是从设备节点读取的原始输入事件,另一类则是输入设备可用性变化事件,简称设备事件
2.processEventsLocked对事件进行处理,对于设备事件,此函数对根据设备的可用性加载或移除设备对应的配置信息,对原始输入事件,则在进行转译,封装与加工后将结果暂存到mQueuedListener
3.所有事件处理完毕后,调用mQueuedListener.flush将所有暂存的输入事件一次性地交给InputDispatcher

深入理解EventHub

1.设备节点监听的建立
通过INotify与Epoll机制建立起对设备节点增删事件以及可读状态的监听
EventHub.cpp:EventHub
2.getEvents
使用Epoll的核心是mPendingEventItems数组,它是一个事件池,getEvents包含了原始输入事件读取,输入设备加载/卸载等操作
3.输入设备管理
每个输入设备在dev/input/下有一个设备节点,设备节点包含输入设备的所有信息,EventHub负责在设备节点可用时加载并维护这些信息,并在设备节点被删除时将其移除,名为Device的私有结构体保存
4.原始输入事件的监听与读取
当设备的原始输入事件到来之时,getevents函数将会获得一个Epoll事件,然后根据Epoll事件读取文件描述符的原始输入事件,将其填充到RawEvents结构体并放入buffer中被调用者取走

Paste_Image.png

深入理解InputReader

1.原始输入事件的加工
InputReader:processEventsLocked
->inputReader:processEventsForDeviceLocked
->InputReader:InputDevice::process
InputDevice描述一个输入设备,是一个存储输入设备信息的类
InputMapper是InputReader中实际进行原始输入事件加工的场所
2.InputDevice与InputMapper
inputDevice创建InputReader:addDeviceLocked
->InputReader:createDeviceLocked

Paste_Image.png

3.keyboard类型事件的加工处理
(1)keyboardInputMapper配置(屏幕旋转状态)
(2)键盘扫描码与虚拟键值
扫描码是硬件实现,虚拟键值是操作系统实现
(3)扫描码到虚拟键值的映射
InputReader->KeyboardInputMapper:process
(4)按键事件的加工处理
InputReader->keyboardInputMapper:processKey

4.Touch类型事件的加工处理
(1)Touch类型事件的信息与原始事件的组织方式
(2)TouchInputMapper的体系

![Upload Paste_Image.png failed. Please try again.]

(3)MultiTouchInputMapper的配置
MultiTouchInputMapper的configureRawPointerAxes获取来自设备节点的各项触控信息,同时构建传感器的物理坐标系
TouchInputMapper的configureSurface获取来自DisplayViewPort的屏幕方向以及屏幕坐标系的信息,并计算物理坐标系到屏幕坐标系的差异信息
(4)点击事件的信息收集
InputReader->MultiTouchInputMapper:process
->MultiTouchMotionAccumulator:process
(5)点击事件信息的整合,变换与高级事件的生成

输入事件的派发

1.将事件注入派发队列
InputDispatcher实现了InputListenerInterface,并在InputReader循环的最后,QueuedInputListener调用此接口将InputReader产生的事件以及NotifyXXXArgs结构体的形式提交给InputDispatcher
->InputDispatcher:notifyMotionLocked
->InputDispatcher:enqueueInboundEventLocked

2.派发线程的线程循环
InputDispatcher:dispatchOnce
派发线程的一次循环包括以下三项:
进行一次事件派发,事件的派发工作仅当命令队列中没有命令时才会进行,派发工作会设置nextWakeupTime指明随后休眠时间长短
执行命令列表中的命令
陷入休眠状态

3.派发工作的整体流程
dispatchOnceInnerLocked函数体现派发过程
InputDispatcher:dispatchOnceInnerLocked

4.事件被丢弃的原因
.....
5.Motion事件目标窗口的确定
InputDispatcher:dispatchMotionLocked
三项工作:
对于被丢弃的事件,返回true
为事件寻找合适的窗口,窗口分为普通窗口和监听窗口,普通通过按点和焦点查找,监听窗口则无条件监听所有输入事件
如果成功地找到可以接收事件的目标窗口,通过dispatchEventLocked完成实际的派发工作

6.向窗口发送事件
InputDispatcher:dispatchEventLocked

按键事件的派发

1.将事件注入派发队列

Paste_Image.png

2.额外的派发策略查询
InputDispatcher:dispatchOnceInnerLocked

3.重复按键事件
InputDispatcher:dispatchOnceInnerLocked
->InputDispatcher:dispatchKeyLocked 开启与关闭重复按键模拟
->InputDispatcher:synthesizeKeyRepeatLocked重复按键的生成

4.按键事件派发总结
按键事件通过notifyKey函数进入InputDispatcher,在注入派发队列前,使用DispatcherPolicy的interceptKeyBeforeQueueing函数询问后续的派发策略policyFlag
按键事件在正式派发给窗口前,进行一次额外的派发策略查询,查询的结果保存在keyEntry:interceptKeyResult,结果觉得事件是正常派发,稍后派发还是丢弃
当按键按下到按键抬起之间的时间里,dispatchOnceInnerLocked和dispatchKeyLocked会协同工作完成对重复按键事件的模拟
按键事件的派发目标仅通过焦点方式进行查找

输入事件的发送,接收和反馈

InputDispatcher运行于system_server进程,窗口运行于其它的应用进程中

深入理解InputChannel

InputChannel的本质是一对SocketPair,SocketPair用来实现在本机内进行进程间的通信
InputTransport->InputChannel:openInputChannelPair

Paste_Image.png

连接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

3.InputDispatcher与窗口的连接


Paste_Image.png

事件的发送

派发循环是指InputDispatcher不断地派发队列取出事件,寻找合适的窗口并进行发送的过程,是InputDispatcher线程的主要工作
事件发送循环是InputDispatcher通过Connection对象将事件发送给窗口,并接受其反馈的过程
InputDispatcher->dispatchEventLocked:dispatchEventLocked根据InputTarget中的InputChannel找到对应的Connection
->InputDispatcher:prepareDispatcCycleLocked
->InputDispatcher:enqueueDispatchEntriesLocked
->InputDispatcher:startDispatchCycleLocked
输入事件被InputPublisher以InputMessage的形式写入InputChannel,然后将事件转存到waitQueue中等待窗口的反馈

事件的接收

当InputPublisher将事件以InputMessage的形式写入InputChannel中,窗口端的Looper会因此而被唤醒,并执行NativeInputEventReceiver的handleEvent调用consumeEvent
->android_view_InputEventReceiver->NativeInputEventReceiver:consumeEvent读取一个InputEvent,生成java层的InputEvent对象,最后通过JNI回调
->InputEventReceier:dispatchInputEvent

事件的反馈与发送

->inputEventReceiver:finishInputEvent
->android_view_InputEventReceiver->NativeInputEventReceiver:finishInputEvent触发服务端InputChannel回调
->InputDispatcher:handleReceiveCallback
->InputDispatcher:doDispatchCycleFinishedLockedInterruptible
对于输入事件反馈的处理主要有两个方面
将事件从Connection的waitQueue队列中删除,这个删除动作标志着此事件的派发流程完成
最后调用startDispatchCycleLocked继续尝试发送队列中的下一个事件

输入事件ANR的产生

->InputDispatcher:findFocusedWindowTargetsLocked
1.窗口可以接收事件的条件
->InputDispatcher:isWindowReadyForMoreInputLocked判断窗口是否可以接收事件:InputPublisher是否被阻塞以及Connection两个队列的状态
2.重试派发与ANR的引发
->InputDispatcher:handleTargetsNotReadyLocked

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容