最近在尝试把Android上的游戏手柄的按键给标准化, 通过上下层的分析, 理论上是可行的。

现在先记录下学习的总结。
Android的输入主要分为两部分:
C++层: 一个是底层事件的收集与分发。 (这部分属于 system_process)
Java和C++层: 事件的消费。 (这部分存在于用户的进程)
这两者在不同的进程, 他们的数据传递方式在Android4.1之后是通过SocketPair(我看的是4.4的代码),  Android4.1之前是通过共享内存的方式。
网上的文章也很多描述输入部分的, 但是C++层如何传递数据, 写的一般比较清楚, 而且代码比较清晰。 对于如何传递给Java层的就比较模糊。
所以对于C++层的分析, 我推荐一篇Blog比较全面的介绍 http://blog.csdn.net/myarrow/article/details/7091061 。
这篇文章的重点不在于贴上的代码有多少, 而在与底层实现的思想,配上图, 这样对底层有一个大概的了解。(这篇文章也有比较大的局限性, 对事件如何传递到Java层没有做解释)
本文将分为两个部分介绍:
1) 用户进程InputChannel如何同C++层的InputChannel关联起来的(InputChannel的注册流程)
2) C++层如何向Java层传递事件的, 以及Java层是如何消费这个事件的
附: 介绍Java层事件传递的方式

1) 用户进程InputChannel如何同C++层的InputChannel关联起来的(InputChannel的注册流程)

从ViewRoot.java的setView方法开始分析。
大致的流程图: 
注册的流程:
1: ViewRoot 首先创建一个Java层的InputChannel, 通过WindowSession同WMS交互
2: WMS首先通过InputChannel.openInputChannelPair(name)再Nativie层创建一对InputChannel(Android4.1开始InputChannel是通过Socket实现的, 之前是通过ShareMemory实现的)。
3:上层应用注册接收端的InputChannel
3-1: ViewRoot拿到刚才已经关联到Native层的InputChannel, 用InputChannel和Looper创建一个WindowInputEventReceiver。
3-2: WindowInputEventReceiver在创建的时候, 调用Natice层的NativeInputEventReceiver,把InputChannel注册到Native层的Looper上监听ALOOPER_EVENT_INPUT事件。
[cpp] view plaincopy
  1. int fd = mInputConsumer.getChannel()->getFd();
  2. mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
4:系统服务注册接收端的InputChannel
4-1:InputManager通过Native方法nativeRegisterInputChannel注册服务端的InputChannel
4-2:Native层先保存这个连接, 然后再跟接收端一样在Looper上进行监听。
[cpp] view plaincopy
  1. sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
  2. int fd = inputChannel->getFd();
  3. mConnectionsByFd.add(fd, connection);
  4. mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
整个接收端的注册流程比较简单, 发送端只需要把信息写入发送端的InputChannel中, 接收端就可以接收到信息了。 

2) C++层如何向Java层传递事件的, 以及Java层是如何消费这个事件的

2-1: 一个事件如何从InputDispatcher中发到应用层的

从InputDispatcher中等待事件开始分析:
首先在Looper中等待InputReader往InBoundQueue队列中添加事件。 
1: 由InputReader唤醒InputDispatcher的等待,  开始执行dispatchOnce。
2: 然后在dispatchOnceInnerLocked中, 把事件从InBoundQueue中取出。
3: 对于KeyEvent, 在dispatchKeyLocked中先拿到当前窗口的InputChannel。
4:接着dispatchEventLocked中取得之前服务端保存的Connection。
5:在enqueueDispatchEntriesLocked方法中, 把事件放入outboundqueue队列中(InboundQueue: 同步InputReader和InputDispatcher的,outboundqueue是同步InputDispatcher和InputPublisher )。
6: 再startDispatchCycleLocked中通过InputPublisher开始传递数据。
7: InputPublisher实际是调用InputChannel, 向之前打开的Socket开始写数据, 所以应用程序端的Socket就会被唤醒。

2-2: 应用层如何从C++层相应事件, 以及上层大致的处理思路

传递的基本流程也比较简单:
1: 应用程序由于之前已经在Looper上注册了InputChannel(即Socket), 2-1最后一步向服务端的Socket写入数据, 所以应用程序的Socket就会被唤醒。
2:根据注册的信息, getLooper()->addFd(fd, 0, events, this, NULL);, 所以唤醒后首先执行回调函数 LooperCallback.handleEvent.
3:根据handleevent的events参数判断是否为ALOOPER_EVENT_OUTPUT事件, 接着调用consumeEvents处理。
4: consumeEvents处理主要分为3部:
4-1: 通过InputConsumer.consume构造一个C++层的InputEvent(这部分首先调用客户端的InputChannel.receiveMessage方法, 这个方法的实现就是从Socket的另一端读出刚才服务器端写入的内容)
4-2: 把C++层的InputEvent构造成为Java层的一个对象。
4-3: 最后通过JNI的反向调用, 执行Java代码 env->CallVoidMethod(receiverObj.get(),gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
至此事件从C++层传递到了Java层。

附: 介绍Java层事件传递的方式

Java层事件分为两类一类是KeyEvent和MotionEvent, 对于KeyEvent的事件传递, 刚才2-2的传递流程是OK的。 
对于MontionEvent的传递, android4 加入的Vsync, UI的更新是由Vsync来触发的, 这里Montion事件的传递也是由Vsync来出发的。 (由于UI是有Vsync触发刷新的, 如果Montion事件的传递不是由Vsync触发的话, 可能会导致画面和事件的传递不同步)
KeyEvent事件由于不涉及UI的更新, 所以跟Vsync无关。
由于4.1开始, 再处理UI的时候会阻塞事件的处理, 所以在UI更新完毕之后会主动的调用事件处理函数。
主要代码位于android.view.Choreographer.java
[java] view plaincopy
  1. void doFrame(long frameTimeNanos, int frame) {
  2. final long startNanos;
  3. synchronized (mLock) {
  4. if (frameTimeNanos < mLastFrameTimeNanos) {
  5. scheduleVsyncLocked();
  6. return;
  7. }
  8. mFrameScheduled = false;
  9. mLastFrameTimeNanos = frameTimeNanos;
  10. }
  11. doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
  12. doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
  13. doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
  14. }
事件在Java层的处理,主要在ViewRootImpl.java中先处理。
不论是KeyEvent还是MotionEvent最终的处理都是在doProcessInputEvents中处理。
1: doProcessInputEvents中主要是循环处理所以的事件。
2: 具体的处理位置在doProcessInputEvents, 在这个函数中首先判断是否把事件交由Ime处理。
3: 具体的处理流程: Java层封装成一个链的流程。 如果最终都没有处理掉的事件, 则交给SyntheticInputStage, 它是用来转换一些特殊事件的。(例如 遥感事件就是在这里转换成方向键的)
至此: 把一个事件从C++层如何完整的传递到Java层的流程分析完毕, 整个流程没有贴大量的代码。
因为代码大家都有, 代码多了反而容易迷糊,篇幅冗余,而且代码太多容易抓不住重点, 贴图加上文字描述, 这样整个流程做到了然于胸, 某个过程不明白的可以去看具体代码。

Android4.4 Input 输入上层分析相关推荐

  1. linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例

    1.1    本节阅读前提 本节的说明建立在前两节的基础之上,需要先阅读如下两篇章: linux input输入子系统分析<一>:初识input输入子系统 linux input输入子系统 ...

  2. linux input输入子系统分析《四》:input子系统整体流程全面分析

    1      input输入子系统整体流程 本节分析input子系统在内核中的实现,包括输入子系统(Input Core),事件处理层(Event Handler)和设备驱动层.由于上节代码讲解了设备 ...

  3. linux input输入子系统分析《一》:初识input输入子系统

    主要讲述本人在学习Linux内核input子系统的全部过程,如有分析不当,多谢指正.以下交流方式,文章欢迎转载,保留联系信息,以便交流. 邮箱:eabi010@gmail.com 主页:www.iel ...

  4. linux input输入子系统分析《二》:s3c2440的ADC简单驱动实例分析

    1      mini2440的ADC驱动实例 这节与输入子系统无关,出现在这里是因为后面的章节会讲到触摸屏输入子系统驱动,由于触摸屏也使用ADC,因此本节是为了说明ADC通过驱动代码是如何控制的. ...

  5. Linux驱动分析——input输入子系统

    stm32mp157  盘古开发板  Linux内核版本4.19 目录 1.朱有鹏老师的视频课程笔记和应用测试代码: 2.input子系统架构分析 2.1.输入核心层源码分析 2.1.1.首先是核心模 ...

  6. 7.Linux 输入子系统分析

    为什么要引入输入子系统? 在前面我们写了一些简单的字符设备的驱动程序,我们是怎么样打开一个设备并操作的呢? 一般都是在执行应用程序时,open一个特定的设备文件,如:/dev/buttons 1 .. ...

  7. python3中input输入浅谈_详解Python3中的 input() 函数

    详解Python3中的 input() 函数 一.知识介绍: 1.input() 函数,接收任意输入,将所有输入默认为字符串处理,并返回字符串类型: 2.可以用作文本输入,如用户名,密码框的值输入: ...

  8. linux input系统的分析笔记(一)

    linux input系统的分析笔记(一) 我的学习的思路是:知其然,然后再 知其所以然. 我要得是看得到的结果和现象,然后再想办法改变和理解它的原理. 在android的shell下有个好用的工具: ...

  9. Linux输入事件类型EV_SW,Linux的input输入子系统:总体框架

    一.input输入子系统总体框架 Linux输入子系统将输入驱动抽象为三层:设备驱动层.核心层.事件处理层. 设备驱动层:将底层的硬件输入事件转化为统一事件形式,向输入核心(Input Core)汇报 ...

最新文章

  1. 练习10-1 使用递归函数计算1到n之和 (10 分)
  2. android ffmegp for_FFmpeg 编译for Android
  3. Redis的数据类型详解
  4. Python中国际化(i18n)完整指南
  5. abs int 宏定义_在标准C中,预处理语句,特别是宏定义中,常常出现'#'和'##'符号,#字符串创建运算符#...
  6. css 元素 property value计算过程的学习笔记
  7. 如何在CircleCI上构建支持Graal的JDK8?
  8. 学 Python 没找对路到底有多惨?| 码书
  9. OpenCV c接口与c++接口
  10. ug80浩强工具_浩强工具下载|浩强UG工具下载 v2.59 最新版 - 比克尔下载
  11. 51单片机c语言秒表,51单片机秒表C程序
  12. Java 从入门到放弃?
  13. 计算机日期型函数公式,excel函数公式应用:日期格式转换公式大全-excel技巧-电脑技巧收藏家...
  14. XShell VIM 粘贴
  15. python计算器实验报告_python作业模拟计算器开发(第五周)
  16. 一条互联网广告多少钱?
  17. 游戏服务端框架之配置与玩家数据库设计
  18. 基于项目的协同过滤推荐算法单机版代码实现(包含输出电影-用户评分矩阵模型、项目相似度、推荐结果、平均绝对误差MAE)
  19. java开发人员的小习惯
  20. Android RSA加密解密的 工具类的使用

热门文章

  1. 对象序列化(六):应用实例-程序退出时保存状态
  2. LR学习笔记七 之 LR录制sql脚本
  3. 开源公司黄页之腾讯开源软件推荐
  4. AngularJS Provider/Service/Factory 使用
  5. OpenEphyra学习笔记1
  6. Linux学习笔记 --网络配置及进程管理
  7. mysql命令行导入dmp文件,oracle的备份文件(dmp)导入mysql数据库方法
  8. mft文件记录属性头包括_学懂主流NTFS分区文件系统,你也可以成为MM眼中的大神!...
  9. java宠物实训报告,基于Java的宠物用品商城的设计与实现-开题报告
  10. 我大学时代的好朋友要结婚了!