Android 按键消息流程源码分析

在Android系统中,键盘按键事件是由SystemServer服务来管理的;然后在以消息的形式分发给应用程序处理。产生键盘按键事件则是有Linux kernel的相关驱动来实现。键盘消息有别于其他类型的消息;需要从Linux kernel drivers产生由上层APP来处理。同时按键有着不同的映射值,因此从模块独立性角度各个独立的模块应该拥有不同的键盘映射。这样以来,kernel产生的按键事件必然回经过不同的映射才到APP。
Android使用标准的Linux输入事件设备(/dev/input/)和驱动按键定义在Linux内核include/linux/input.h中,按键的定义形式如下(仅以BACK HOME MENU为例):
在这里插入图片描述

Kernel内核驱动会产生事件,在这里就不讨论了,不是本文的范畴;下面分析Framework事件处理流程。

SystemServer.java
在这里插入图片描述

可以看到,在系统启动的时候,会首先创建一个系统级别的Handler线程wmHandlerThread用于处理键盘消息(仅说明键盘消息)。然后在创建输入管理服务inputManager,InputManagerService的第二个参数就是用于处理按键消息的Handler。

InputManagerService.java
进入InputManagerService的构造函数:
在这里插入图片描述

这里做了重要的两件事情,第一:将SystemServer级别的Handler赋值给InputManagerService自己的消息处理Handler;第二:调用nativeInit继续进行初始化。

com_android_server_input_InputManagerService.java
那就看看本地初始化:
在这里插入图片描述

进入NativeInputManager构造函数:
在这里插入图片描述
这里需要特别注意最后两行代码。第一:创建了EventHub;第二:创建InputManager并将EventHub作为参数传入InputManager。

InputManager.cpp
接下来继续看看InputManager的构造函数:
在这里插入图片描述
创建了InputDispatcher和InputReader,请注意00032行,mDispatcher作为了InputReader参数,你看看InputReader的构造函数就知道为什么要这么做了;后面调用了initialize函数创建了InputReaderThread和InputDispatcherThread。InputDispatcher类是负责把键盘消息分发给当前激活的Activity窗口的,而InputReader类则是通过EventHub类来实现读取键盘事件的,InputReader实列mReader就是通过这里的InputReaderThread线程实列mReaderThread来读取键盘事件的,而InputDispatcher实例mDispatcher则是通过这里的InputDispatcherThread线程实例mDisptacherThread来分发键盘消息的;到这里,相关的组件都已经被创建了。
在systemServer.java中创建inputManager之后。将InputManagerServer进行注册,并运行start()(在第一页有相关代码)。

com_android_server_input_InputManagerService.java
会来到这里:
在这里插入图片描述

继续往下则会调用到InputManager.cpp的start()函数:
在这里插入图片描述
这个函数主要就是分别启动一个InputDispatcherThread线程和一个InputReaderThread线程来读取和分发键盘消息的了。这里的InputDispatcherThread线程对象mDispatcherThread和InputReaderThread线程对象mReaderThread是在前面的第三页中创建的,调用了它们的run函数后,就会进入到它们的threadLoop函数中去,只要threadLoop函数返回true,函数threadLoop就会一直被循环调用,于是这两个线程就起到了不断地读取和分发键盘消息的作用

在这里插入图片描述

继续看loopOnce()这个函数:
在这里插入图片描述
这里面需要注意像神一样的函数mEventHub->getEvents()。其实现原理,还有点不是很清楚;但是其功能就是负责键盘消息的读取工作,如果当前有键盘事件发生或者有键盘事件等待处理,通过mEventHub的**getEvent(这个函数里面很有讲究,有空自己分析,这里不做深入的讲解)**函数就可以得到这个事件,然后交给processEventsLocked函数进行处理。同样需要特别注意最后一行(太长了,没有截过来);后面回解释。我们还会回来的…不过还想补充一点的就是,读取的数据的路径为:
在这里插入图片描述

机型为OK1000:
在这里插入图片描述

通过getEvents获取事件消息后,就得开始处理消息了,回到第六页00314行:
在这里插入图片描述

如果是一般的消息就调用*processEventsForDeviceLocked()*函数;否者去处理设备的ADDED、REMOVED、SCAN事件;那我们就先分析设备的ADD吧,因为后面的处理是在这个基础上的,回到上一页00372行:
在这里插入图片描述

在行00400create一个InputDevice:
在这里插入图片描述

所有类型的设备都在这里生产,然后统一添加到00412行的mDivices;提供给后续具体设备处理,下面就是具体设备的处理过程。
在第七页*processEventsForDeviceLocked()*函数,根据deviceId来处理相应的事件消息:
在这里插入图片描述
我就在想:问什么不直接到process函数呢?其实我觉得这里体现了设计模式中的单一职责原则(多态);这种设计可以有效的控制函数粒度(有个类粒度,这里自创函数粒度)的大小,函数承担的职责越多其复用的可能性就越小,并且当期中某一个职责发生变化,可能会影响其他职责的运作!继续往下走吧…
在这里插入图片描述

这里的每一个事件都要做一个循环处理,代码在01022行,至于为什么你看(行00993)注释就会明白了。
在这里插入图片描述

行02107函数processKey的原型中,有部分代码片段如下:
在这里插入图片描述
看到关键行02216了吧!再回头看看第三页就知道跳转到哪里去了。

总结:
在这里插入图片描述

一不小心来到了这里…
InputDispatcher.cpp
在函数notifyKey中有这样的代码片段:

在这里插入图片描述

行02421函数的功能其实很简单,主要是把EventEntry添加到一个待发的事件队列当中,源代码如下:
在这里插入图片描述

在看看行02424,功能就是唤醒InputDispatcherThread线程,然后就开始执行InputDispatcher的threadLoop函数,之后就调用InputDispatcher的dispatchOnce方法,代码如下:
在这里插入图片描述

进入行00230,其中有这样代码片段:
在这里插入图片描述

进入行00365,其中有这样代码片段:
在这里插入图片描述

行00780,查找焦点窗口,然后进入行00794
dispatchEventLocked()->
prepareDispatchCycleLocked()->
enqueueDispatchEntriesLocked()->
startDispatchCycleLocked()->

其中函数startDispatchCycleLocked()有这样代码片段:
在这里插入图片描述

看到publishKeyEvent()了吧!

InputTransprot.cpp
在这里插入图片描述

继续走:
在这里插入图片描述
总算send出去了。

总结:
在这里插入图片描述

至于外面怎么接收到消息的,后续再分析,内容太多了,自己还没有完全搞懂,等搞懂了再补上…

参考文献:
http://blog.sina.com.cn/s/blog_6268defa0101ad1o.html
http://www.cnblogs.com/haiming/p/3318614.html
http://blog.chinaunix.net/uid-27167114-id-3347185.html
http://my.oschina.net/u/994235/blog/294227
http://blog.csdn.net/zjq2008wd/article/details/39225539
http://blog.csdn.net/powq2009/article/details/8426271
http://blog.sina.com.cn/s/blog_89f592f50101394l.html
http://www.cnblogs.com/lcw/p/3374466.html
http://blog.sina.com.cn/s/blog_89f592f50101394l.html
http://blog.csdn.net/zjq2008wd/article/category/1283349

觉得本文对您有用,麻烦点赞、关注、收藏,您的肯定是我创作的无限动力,谢谢!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/606031.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据链路层——以太网协议

一、以太网的MAC帧格式 源地址与目标地址代表的是网卡的硬件地址,MAC 地址,在出厂时已经确定好了。 帧协议类型有三种值,IP0800,ARP 请求及应答0806,RARP 请求/应答8035. MAC地址一般都是唯一的,长度48位&…

Unity Editor 找物体助手

找啊找朋友~ 🍱功能介绍🥙使用方法 🍱功能介绍 💡输入相关字符串,它会帮你找到名称中带有该字符串的所有物体,还会找包含该字符串的Text、TextMeshProUGUI。 🥙使用方法 💡导入插…

240多道!Go开发岗位面试题合集(含答案)

随着今年互联网寒潮环境的影响,找工作的人也将达到顶峰,今天给大家分享一份《Go开发工程师超高频面试真题》,一共有240多道面试真题,希望能够帮助大家在面试中,少走一些弯路、更快拿到offer! 内容展示 GO 基…

集成逻辑分析器( ILA)IP核用法详解

集成逻辑分析器(Integrated Logic Analyzer, ILA)IP核是一个可定制的逻辑分析器,用于监测设计的内部信号。ILA核心包含了现代逻辑分析器的许多高级特性,比如布尔触发方程(boolean trigger equations)和边沿…

gitignore配置不生效记录

第一种可能性: 在你所有的文件都通过了git add . 命令的情况下,使用指令git rm -r --cached .进行缓存清除,完成之后,再次通过git add . 然后通过git status去看提交的文件都有哪些。 第二种可能性 如果上面的不行就是你添加的…

Makefile经验总结

文章目录 0.概述1.常用规则1.1 清空目录的规则1.2 文件搜寻 (用起来比较爽)1.3 伪目标(可用生成多个目标和配置工程删除规则)1.4 静态模式(用起来也很爽)1.5 显示命令(有助于调试makefile&#…

[YOLOv8] 用YOLOv8实现指针式圆形仪表智能读数(一)

最近研究了一个项目,利用python代码实现指针式圆形仪表的自动读数,并将读数结果进行输出,若需要完整数据集和源代码可以私信。 目录 🍓🍓1.yolov8实现圆盘形仪表智能读数 🙋🙋2.仪表目标检测…

Sui主网升级至V1.24.1版本

其他升级要点如下所示: GraphQL #17313 不再存在 Live 或 Historical 的 ObjectKind,它们已经合并为单个 Indexed 类型,表示从索引中获取的任何对象(而不是我们有相关信息但尚未建立索引的对象, 或者已被删除或包装…

什么才是正确的领域驱动实现架构?

作为一种系统建模方法,DDD同样涉及系统的体系架构设计。区别于分布式、事件驱动、消息总线等架构设计方法,DDD中的架构设计关注前面各章所介绍的聚合、实体、值对象、领域事件、应用服务以及资源库之间的交互方式和风格,并在设计思想上有其独…

创建和管理数据库

1. 一条数据的存储过程 存储数据是处理数据的第一步.只有正确的把数据存储起来,我们才能进行有效的处理和分析.否则,只能是一团乱麻.在MySQL中,一个完整的数据存储过程一共有四步 : 创建数据库,确认字段,创建数据表&a…

[图解]SysML和EA建模住宅安全系统-01

1 00:00:00,980 --> 00:00:03,100 接下来,我们来看一下案例 2 00:00:04,930 --> 00:00:06,750 我们这次课程的案例 3 00:00:07,090 --> 00:00:13,800 选用了SysML实用指南的书上 4 00:00:13,810 --> 00:00:16,180 第十七章这个案例 5 00:00:16,350 …

RSAC 2024现场:谷歌展望大模型在网络安全领域的前景

人类距离将网络安全的控制权交给生成式AI还有多远? 前情回顾RSAC2024动态 伪造内容鉴别厂商Reality Defender斩获2024 RSAC创新沙盒冠军 RSAC 2024上值得关注的10款网络安全产品 RSAC 2024创新沙盒十强出炉,谁能夺冠? 安全内参5月8日消息…

代码随想录算法训练营第二十一天:树树树

代码随想录算法训练营第二十一天:树树树 ‍ 513.找树左下角的值 力扣题目链接​**(打开新窗口)** 给定一个二叉树,在树的最后一行找到最左边的值。 示例 1: ​​ 示例 2: ​​ #算法公开课 《代码随想录》算法视频公开课…

跨平台美学!使用DevExpress Reports Office File API时如何管理字体?

DevExpress Office File API是一个专为C#, VB.NET 和 ASP.NET等开发人员提供的非可视化.NET库。有了这个库,不用安装Microsoft Office,就可以完全自动处理Excel、Word等文档。开发人员使用一个非常易于操作的API就可以生成XLS, XLSx, DOC, DOCx, RTF, CS…

鲁大师4月电动两轮车榜:RideyFUN Air智驾系统上线,九号F2z 110智能化再升级

鲁大师4月电动两轮车排行榜数据来源于鲁大师智慧实验室,测评的车型均为市面上主流品牌的主流车型。截止目前,鲁大师智能化电动车测评的车型高达160余台,且还在不断增加和丰富中。 鲁大师电动车智能化测评体系包含车辆的状态采集与管理硬件系统…

android基础-通知

基于第一行android 使用PendingIntent来实现点击通知跳转到另一个活动。 notificationcompat.builder后面可以跟很多的方法,不同方法不同效果,比如加一个音频.setSound(uri) 内置网页 解析json

Spring IoCDI(1)—入门

目录 一、IoC & DI入门 1、Spring是什么 (1)什么是容器? (2)什么是IoC? 二、IoC介绍 1、传统程序开发 2、解决方案 3、IoC程序开发 4、IoC优势 三、DI介绍 通过前面的学习,我们知…

开源即时通讯IM框架 MobileIMSDK v6.5 发布

一、更新内容简介 本次更新为次要版本更新,进行了bug修复和优化升级(更新历史详见:码云 Release Notes、Github Release Notes)。 MobileIMSDK 可能是市面上唯一同时支持 UDPTCPWebSocket 三种协议的同类开源IM框架。轻量级、高…

OpenGVLab/InternVL-Chat-V1-5-Int8

openedai-vision 代码仓库 OpenGVLab/InternVL-Chat-V1-5-Int8 模型文件地址 示 算力平台AutoDL df -h /root/autodl-tmp tar -xvf FileName.tartar -xvf 安装 克隆我们的仓库并跳转到相应目录 2. 创建 conda 环境 cond…