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

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MWM触摸屏工控机维修TEM-EV0 EN00-Z312yy-xx

触摸屏维修是一个比较复杂的过程,并且其中会涉及到各个部件的问题,这对于操作人员来说,关键在于是否可以找到问题所在。维修过程中建议先检查各接线接口是否出现松动,然后检查串口及中断号是否有冲突,若有冲突&#xf…

Ubuntu20.04 设置路由器

1. 网络拓扑图 双网卡单Lan口拓扑图 多网卡多Lan口带网桥拓扑图 2. 查看网卡信息 ip a得出如下网卡信息列表,共四个网络信息,忽略第一个本地环回地址 一共存在三个网卡分别为enp1s0、enp2s0、wlo,以及其他详细信息,当前我们只需…

【Linux系统编程】第十八弹---进程状态(上)

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、操作系统进程 1.1、进程背景 1.2、进程如何在CPU上运行的? 1.2、进程状态 2、Linux的进程状态 2.1、如何描…

U盘打不开提示格式化怎么办?(含数据恢复及U盘修复教程)

引言: 随着数字化时代的发展,U盘已成为我们日常生活和工作中不可或缺的数据存储工具。然而,有时我们可能会遇到U盘突然无法打开,并提示需要格式化的问题。这不仅会打乱我们的工作节奏,还可能会导致重要数据丢失。本文…

【SpringSecurity源码】过滤器链加载流程

theme: smartblue highlight: a11y-dark 一、前言及准备 1.1 SpringSecurity过滤器链简单介绍 在Spring Security中,过滤器链(Filter Chain)是由多个过滤器(Filter)组成的,这些过滤器按照一定的顺序对进…

基于SpringBoot+Vue的法律咨询系统

课题背景 二十一世纪互联网的出现,改变了几千年以来人们的生活,不仅仅是生活物资的丰富,还有精神层次的丰富。在互联网诞生之前,地域位置往往是人们思想上不可跨域的鸿沟,信息的传播速度极慢,信息处理的速…

Kafka应用Demo:按主题订阅消费消息

安装环境 Kafka安装可参考官方网站的指导(https://kafka.apache.org/quickstart), 按步骤解压压缩包,修改配置。然后再启动zookeeper和kafka-server即可。 需要注意的一点:如果是在VMware虚拟机上启动的kafka, 需要修改一下server.properties配置文件&am…

AI浪潮再起,2024年中国大模型产业深度解析

国内 AI大模型产业发展深度分析 2024 人工智能技术的迅猛发展,使AI大模型成为科技竞争的核心、产业变革的先锋、经济增长的新动力。我国已将人工智能列为国家战略,出台系列政策扶持其发展,为AI大模型产业创造优越环境,展现巨大潜力…

CentOS 7安装配置docker

CentOS 7、8安装、配置docker 这里宿主机的型号选择是centos7.9.2009的版本 1.宿主机关闭防火墙和selinux,配置ipv4 #设置SELinuxdisabled vim /etc/selinux/config SELinuxdisabled 查看防火墙状态:firewall-cmd --state 关闭防火墙:syst…

FloodFill算法---BFS

目录 一、前言 二、算法模板套路 2.1 创建所需的全局变量: 2.2 BFS模板: 2.3 细节处理: 三、例题练习 3.1 例题1:图像渲染 3.2 例题2:岛屿数量 3.3 例题3:岛屿的最大面积 3.4 例题4:被…

在做题中学习(54):点名

LCR 173. 点名 - 力扣(LeetCode) 此题有不同的几种解法: 解法一:暴力枚举 O(n); 解法二:哈希表 把原数组丢入哈希表,遍历哈希表,看看哪个数值为0即可。 O(n)空间O(n)时间 解法三&…

OpenAI推出新模型GPT-4o:可实时交互,检测人的情绪,支持多模态输出

GPT-4o作为OpenAI新发布的人工智能模型,据官方及媒体报道,是面向全球用户发布的,包括中国在内的用户理论上应该能够通过相应平台和应用访问。不过,实际可用性还需考虑地区政策、网络访问限制以及具体平台是否在中国有本地化服务等…

1694jsp宿舍管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 宿舍管理系统 是一套完善的web设计系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统采用web模式,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库…

网络安全快速入门(十一)vi/vim

11.1 了解vi 前面我i们已经在基础命令中大致了解了vi,本章我们针对vi来细讲一下,vi和vim 11.1.1 什么是vi/vim? vi和vim,都是一个模块化的文本编辑工具,换句话讲,通过vi下的一系列的命令,可以实…

Redis 源码安装和入门介绍

Linux下的redis源码安装 redis介绍 Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,如 字符串(strings),…

专访安克创新CEO阳萌:仿生算法与存算一体芯片的兴起

在这篇博客中,我们将探讨人工智能的未来发展方向,特别是围绕大模型、存算一体芯片以及仿生算法的讨论。通过对安克创新CEO阳萌的专访内容进行分析,我们将尝试解答一些关于AI发展的关键问题,并对未来的技术趋势进行预测。 引言 …

AD原理图设置:如何在编译工程时,报未连接线或引脚错误

如下图,AD默认在编译原理图时,如果出现未连接的引脚或线时,并不会报相关的错误,这样做其实很危险 所以,我们应该让它提示错误 具体配置方法: 1、找到工程选项 2、切换到第二个选项“Connection Matrix”&a…

OBS插件--源录制

源录制 将应用这个滤镜的源录制成视频保存下来,可以选择音轨,也可以针对应用此滤镜的源单独的推流等。 如果在直播或录制视频的过程中场景里面布置了多个源,而只想保存其中一个源的视频或音频这个插件非常使用。 下面截图演示下操作步骤&a…

面试中的算法(查找缺失的整数)

在一个无序数组里有99个不重复的正整数,范围是1~100,唯独缺少1个1~100中的整数。如何找出这个缺失的整数? 一个很简单也很高效的方法,先算出1~100之和,然后依次减去数组里的元素,最后得到的差值,就是那个缺…

数据库入门(sql文档+命令行)

一.基础知识 1.SQL(Structured Query Language)结构化查询语言分类: DDL数据定义语言用来定义数据库对象:数据库、表、字段DML数据操作语言对数据库进行增删改查DQL数据查询语言查询数据库中表的信息DCL数据控制语言用来创建数据…