android input 系统----1

来源:互联网 发布:linux 关 firewall 编辑:程序博客网 时间:2024/06/04 18:19

 

android输入事件上报概况

       android怎么获取输入事件?输入事件怎么派发到对应的窗口上?

1、android input设计思想

     

      驱动侦听到用户在不同设备上的input事件,将事件输出到文件中,android通过监听这些文件来得知事件的上报,然后派发给对应的view。以下是手机系统中的事件输出文件,每个文件代表一种或者多种事件类型。

[plain] view plaincopyprint?
  1. add device 1: /dev/input/event0  
  2.   name:     "lsm303dlhc_acc"   
  3. add device 2: /dev/input/event1  
  4.   name:     "lsm303dlhc_mag"   
  5. add device 3: /dev/input/event5  
  6.   name:     "7k_handset"      
  7. add device 4: /dev/input/event4  
  8.   name:     "7x27a_kp"      
  9. add device 5: /dev/input/event3  
  10.   name:     "ft5x0x_ts"      
  11. add device 6: /dev/input/event2  
  12.   name:     "tmd2771x"    
add device 1: /dev/input/event0  name:     "lsm303dlhc_acc" add device 2: /dev/input/event1  name:     "lsm303dlhc_mag" add device 3: /dev/input/event5  name:     "7k_handset"    add device 4: /dev/input/event4  name:     "7x27a_kp"    add device 5: /dev/input/event3  name:     "ft5x0x_ts"    add device 6: /dev/input/event2  name:     "tmd2771x"  

lsm303dlhc_acc: msensor

lsm303dlhc_mag:gsensor

7k_handset:耳机插拔事件

7x27a_kp:keypad 主要是一些物理按键的事件,音量加减键等

ft5x0x_ts:tp,这里包含虚拟按键、屏幕的touch事件等

tmd2771x:psensor 和lsensor

2、功能分析

    对应的设备驱动监听到事件的改变就会将对应的事件写入到上述的文件中,android 监听到这些文件有变化就读取当前的事件,然后派发。

   android framework有两个线程负责读取和派发,它们是在初始化wms时启动的,然后一直运行,其中InputReaderThread负责读取设备文件中的事件,InputDispatcherThread线程负责派发获取到的事件。

    派发事件,对于key来说会在wms中进行预处理,然后才会派发到对应的窗口上,touch事件会直接派发到对应的窗口上,android是怎么派发到客户窗口的呢?在android 2.3以后采用管道的方式,以前的版本采用binder通信。客户窗口事先会注册好管道,在客户进程通过读取管道中事件,然后进行窗口内部的派发。

 

 

 

 

====================================================================================================================================

                                                                                          第二部分:详细分析

 

 

项目:峥一                                                           reboot  -p  关机命令

第一部分linux

设备驱动---->注册input子系统----->上报---->android 上面getevent就有了健值

1.#getevent

触摸屏:/dev/input/event5: x和y的坐标值----------  name:     "ft5x02"

电源按键:/dev/input/event1  上报健值是74------------------- name:     "axp20-supplyer"

音量按键:/dev/input/event0   上报健值是72和73------------  name:     "sun4i-keyboard"

add device 4: /dev/input/event3
  name:     "headset detect"
add device 5: /dev/input/event2
  name:     "simcard detect“

问题:1.此时这个按键值是上报给android的,linux 上报时什么?设备驱动?

            2.虚拟按键的问题?

--------------

2.lichee\linux-3.0\drivers\input\keyboard\sun4i-keyboard.c  -----------音量按键

  input.h中定义#define KEY_VOLUMEDOWN  114 ----------------------------十六进制是72----------------------刚好

 getevent event0的健值也是72.

 

3..阅读getevent的代码。代码为./core/toolbox/getevent.c

从代码中,我们知道,程序在while(1)的一个死循环里,不断地在读取 (select操作)/dev/input 下面的文件,检查是否Kernel往里面更新内容,如果有内容更新,就把它打印出来。并且从代码中,我们还知道,任何一个event都有三种属性,type,code,value.

  备注:内核上报的时候是向/dev/input  写数据---------

 

4.问题来了,Android Framework是否也是一样的原理呢??

    我们从Kernel层往上看,先看看Framework,直接操纵/dev/input设备的代码。

   4.1  frameworks/base/services/input/EventHub.cpp 中,我们看到跟getevent工具类似的代码

        EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize)

       说明:读linux上报的输入信息到  RawEvent* event(局部变量)-----------内部调用函数device->keyMap.keyLayoutMap->mapKey处理------------?

   4.2.那么framework中那个模块再调用EventHub呢,接着往下查。

    

  # find . -name "*.cpp" |grep -v EventHub | xargs grep EventHub

.  从查找结果中得知,在jni文件com_android_server_KeyInputQueue.cpp文件中有对EventHub进行调用。

   在下面的函数中调用了EventHubgetEvent函数

 

static jboolean

android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,

                                          jobject event)

 

 

 

4.3.根据jni的调用规则,在本文件中查找对于的java函数

 

static JNINativeMethod gInputMethods[] = {

 

    /* name, signature, funcPtr */

    { "readEvent",       "(Landroid/view/RawInputEvent;)Z",

            (void*) android_server_KeyInputQueue_readEvent },

 

7. 接着顺藤摸瓜,找到对应的java文件,base/services/java/com/android/server/KeyInputQueue.java

private static native boolean readEvent(RawInputEvent outEvent);

 

在一个线程中会调用readEvent函数。

8.那是谁启动这个线程呢???查找mThread变量,得知在KeyInputQueue的构造函数中会启动这个线程。

9.那这个KeyInputQueue是在哪里被实例化呢?

 

而且查看KeyInputQueue类的声明,得知它是一个abstract class.

 

说明它肯定会被某个类继承.接着查找。

 

/frameworks$ find . -name "*.java" |grep -v KeyInputQueue | xargs grep KeyInputQueue

 

10.从上面的查找结果得知,会在WindowManagerService.java中有一个KeyQ类继承KeyInputQueue类,再在这个文件中查找KeyQ类在哪里定义并实例化的,找到在其构造函数里实例化的。

至此,基本上把Input eventFramework的流程全部走完了。WindowManagerService是属于System server进程里面起的一个Service.一开机就会运行,当然其构造函数一开机就能会运行。

 

至此,整个流程如下:

 

               WindowManagerService

 

                             |

 

                             |

 

                            \/

 

                         KeyQ

 

                             |

 

                             |

 

                            \/

 

                        KeyInputQueue

 

                             |

 

                             |

 

                            \/

 

                        EventHub

 

                             |

 

                             |

 

                            \/

 

                         Kernel device (/dev/input)

 

后续的文章将介绍/dev/inputKernel中的实现。

 

 

 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第二部分android