Android Input事件获取与分发简单总结

一、整体流程

系统Input事件传递主要经过如下几个部分:

1.1输入系统部分

输入子系统

手机的输入设备(包括屏幕、键盘、鼠标等),当前可用,会在文件系统/dev/input中创建对应的设备节点,用户操作输入设备会产生输入事件(按键事件、触摸事件、鼠标事件)等。

/dev/input/event0
/dev/input/event1
/dev/input/event2
...

InputManagerService
IMS初始化过程主要构造了如下结构:

从结构看,IMS核心功能实现在Native层:

  • IMS由SystemServer创建。

  • 在system_server进程中包含两个重要的线程InputReaderThread和InputDispatcherThread,其内部分别对应InputReader和InputDispatcher两个工作类。

  • InputReader负责读取底层收集的input事件:从EventHub读InputEvent并且传给InputDispatcher来进行分发。

  • InputDispatcher负责分发input事件到应用层。WindowManagerService在app端setView的时候就创建了一对Socket连接,InputDispatcher利用这个Socket连接和app端通信。

1.2 WMS处理部分

WMS的职责之一就是输入系统的中转站,WMS作为Window的管理者,会配合IMS将输入事件交由合适的Window来处理。

1.3 View处理部分

app端的ViewRootImpl里面的InputEventReceiver会接到从Socket得到的InputEvent。最终走APP的事件传递,消费事件。

二、InputManagerService初始化过程

通过流程图可以看出,这部分主要是做了一系列的初始化工作:

  • startOtherServices中,创建了IMS以及WMS,并将WMS中的monitor传给了IMS,作为回调,最后启动IMS。

  • IMS的初始化中执行了nativeInit,该方法中创建了一个NativeInputManager实例,并且和java层使用的是同一个looper。

  • 在NativeInputManager的初始化中创建了一个Eventhub,同时将这个Eventhub传给新建的Inputmanager,Eventhub就是将数据从硬件驱动上读出来然后传递上来的通道。

  • InputManager初始化时创建了两个重要线程:InputReaderThread和InputDispatcherThread。

  • InputManager的start方法,让两个线程开启了循环执行操作。

三、InputReader处理InputEvent流程

简单总结:

  • InputReader启动后执行loopOnce,它是一个可阻塞循环。

  • loopOnce循环中会通过Eventhub调用getEvents,来获取底层input事件,getEvents其实分成了三部分,首先是进行device的读取和处理,扫描/dev/input/目录来生成device数据。二是看有没有需要处理的时间,如果有那么就处理了返回。最后是进行等待,等待对应事件的发生。

  • 读到了事件就会调用processEventsLocked处理事件:循环获取EventHub给过来的事件,这里事件包括来自Kernel的input事件和对Input事件的插入和删除操作(这个不管),针对Kernel的input事件,交给processEventsForDeviceLocked处理。

  • processEventsForDeviceLocked 调用对应的InputDevice处理Input事件,而InputDevice又会去匹配上对应的InputMapper来处理对应事件。(在InputDevice中,存储着许多InputMapper,每种InputMapper对应一类Device,例如:Touch、Keyboard、Vibrator等等……)而调用InputDevice的process函数,就是将Input事件传递给每一个InputMapper,匹配的InputMapper就会对Input事件进行处理,不匹配的则会忽略。

  • InputMapper将数据综合打包成三种数据封装:NotifyKeyArgs、NotifyMotionArgs和NotifySwichArgs,分别对应key、Motion和Swich事件。

  • 最后调用mQueuedListener->flush(),将事件队列中的所有事件交给在InputReader中注册过的InputDispatcher。InputDispatcher先于InputReader被创建,InputDispatcher没有输入事件处理时会进入睡眠状态,等待InputReader通知唤醒。InputDispatcher的notifyKey函数中会根据按键数据来判断InputDispatcher是否要被唤醒,InputDispatcher被唤醒后,会重新调用dispatchOnceInnerLocked函数将输入事件分发给合适的Window。

InputReader从EventHub获取input event,将input event打包成Args放到InputDispacher的mInboundQueue,然后通过notifyKey唤醒InputDispacher。

四、InputDispatch分发流程

简单总结:

上节InputReader把input event放入了mInboundQueue(NotifyMotionArgs转换为MotionEntry,添加到队尾)。InputDispatcherThread被唤醒后,通过InputDispatcher主要任务是找到对应的window,并建立进程间通信,把input event 传递过去。

  • InputDispatcher中,由dispatchOnceInnerLocked处理input event:

1)从mInboundQueue取出事件
2)通过EventEntry的类型,对不同事件进行不同处理,下面以TYPE_KEY为例
3)TYPE_KEY对应会执行dispatchKeyLocked,将事件分发出去

  • dispatchKeyLocked中做三件事情:

1)postCommandLocked 让policy处理Home、Menu等系统按键,policy对应的是NativeInputManager
2)findFocusedWindowTargetsLocked 判断发生按键事件的Window并得到对应的inputTargets
3)dispatchEventLocked 通过InputTarget获取对应的Connection,每个焦点窗口在InputDispacher里都有一个对应的Connection,通过这个Connection可以跟InputDispacher通信。然后发送事件EventEntry,先是将eventEntry放入Connection的outboundQueue,再通过InputPublisher将Entry发送给窗口,再将Entry从outboundQueue移到waitQueue里,最后由InputPublisher调用InputChanel的SendMessage(),SendMessage()再动用socket的send()函数,将打包好的Message发送给窗口。

  • InputChannel封装了窗口与InputDispatcher间的跨进程通信

应用在ViewRootImpl的setView(),最终会调用IWindowSession的addToDisplay()函数,该函数带上了mInputChannel参数,向WMS注册Channel。

五、App端处理流程

简单总结:

  • WindowInputEventReceiver中的onInputEvent回调执行enqueueInputEvent,从队列中获取一个QueuedInputEvent,判断是立刻执行还是延迟执行,但是最终都会走doProcessInputEvents。

  • doProcessInputEvents中主要通过deliverInputEvent进行事件分发。这里核心是InputStage体系,责任链模式。最终会匹配上对应Stage来进行事件分发处理。

  • 以Activity,View的按键分发流程相关的InputStage:ViewPostImeInputStage为例,执行ProcessKeyEvent

第一步是调用PhoneWindow.DecorView的dispatchKeyEvent函数,DecorView是View层次结构的根节点,按键从根节点开始按View的事件传递流程走。

第二步是判断按键是否是四向键,或者是TAB键,如果是则需要移动焦点。

本文只是参考了网上的文章,针对input系统总结了一个模糊的流程,input总体来看还是比较复杂的,想要深入学习还是需要针对源码进行详细分析。

参考
https://zhuanlan.zhihu.com/p/29152319
https://blog.csdn.net/urdfmqcul2/article/details/78146424
https://blog.csdn.net/xingchenxuanfeng/article/details/79208005
https://blog.csdn.net/chenweiaiyanyan/article/details/72884141

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

推荐阅读更多精彩内容