Android 4 0 事件输入 Event Input 系统

本文详细探讨了Android 4.0中事件输入系统的变化,包括TouchScreen功能在4.0下的问题及原因分析,系统如何管理各种驱动设备,各个功能模块的产生、工作流程和事件处理过程。重点讲解了EventHub、InputReader、InputDispatcher和InputManager的角色和职责,以及设备操作流程。通过对事件从打开设备到分发输入的完整流程解析,揭示了Android 4.0事件输入系统的工作机制。
摘要由CSDN通过智能技术生成

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

 1. TouchScreen功能在Android4.0下不工作

       原来在Android2.3.5下能正常工作的TouchScreen功能,移植到Android 4.0就不能正常工作了。凭直觉,Android4.0肯定有鬼。真是不看不知道,一看吓一跳。在Android 4.0中,Event Input地位提高了,你看看,在Adroid2.3.5中,它在frameworks/base/libs/ui之下,在Android4.0中,它在frameworks/base/services/input之下,看到没有,它有了自己的地位,就像在Kernel中一样,有自己门户了。

      再看看代码,变化也太大了,当然TouchScreen不能工作,首先自然会看接口部分代码。首先看它是如何打开设备的,查看函数EventHub::openDeviceLocked,看看其代码,大部分还是很熟悉的,但仔细一看多了一个下面的东东:

ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);

      由于升级到Android4.0时,Kernel还是2.6.35,并没有进行升级。既然需要EVIOCGPROP,就就看看evdev.c中的ioctl函数是否支持此功能。一看不支持,再看看Kernel3.0.8<这个Kernel版本与Android4.0是一伙的>,我的乖乖,它已经支持了此功能,详见evdev.c中函数evdev_do_ioctl,这个写得2.6.35中的友好多了,分别处理:固定长度命令、单个可变长度命令和多个可变长度命令。

      对于为什么我的TouchScreen在Android4.0不工作,答案显而易见,我用的Kernel版本不对,当然移植到Android4.0对应的Kernel(Kernel3.0.8)时,TouchScreen驱动本身也需要修改,因为input_dev变化也比较大,比如增加了propbit字段,以供处理上面的ioctl时使用。

 

2. Android 4.0如何管理各种驱动设备

       正是由于遇到上面的问题,才促使自己对Event Input进行深入了解。因为蜻蜓点水不是小弟的性格。

       这个年代干啥都有什么经理,小弟之类的。比如去饭店吃饭,吃到小强了,总是会大吼一声,经理,过来看看,然后谈打折或赔偿的问题。可见经理是不可缺少的,要不然我们找谁来维权啊!

       前面谈到的EventHub,这个一看就是一个做实事的,肯定不是领导,哪它的领导是谁呢? 哪我们就从以下几方面来分析此问题:

       1)每个功能模块是怎么产生的?

       2)读取设备输入流程?

       3)事件分发流程?

3. 各个功能模块是怎么产生的?

      先介绍一下每个模块的工作职责:EventHub, InputReader, InputManager...

3.1 模块功能

3.1.1 EventHub

        它是系统中所有事件的中央处理站。它管理所有系统中可以识别的输入设备的输入事件,此外,当设备增加或删除时,EventHub将产生相应的输入事件给系统。

        EventHub通过getEvents函数,给系统提供一个输入事件流。它也支持查询输入设备当前的状态(如哪些键当前被按下)。而且EventHub还跟踪每个输入调入的能力,比如输入设备的类别,输入设备支持哪些按键。 

3.1.2 InputReader

      InputReader从EventHub中读取原始事件数据(RawEvent),并由各个InputMapper处理之后输入对应的input listener.

      InputReader拥有一个InputMapper集合。它做的大部分工作在InputReader线程中完成,但是InputReader可以接受任意线程的查询。为了可管理性,InputReader使用一个简单的Mutex来保护它的状态。

     InputReader拥有一个EventHub对象,但这个对象不是它创建的,而是在创建InputReader时作为参数传入的。

3.1.3 InputDispatcher

     InputDispatcher负责把事件分发给输入目标,其中的一些功能(如识别输入目标)由独立的policy对象控制。

 

3.1.4 InputManager

     InputManager是系统事件处理的核心,它虽然不做具体的事,但管理工作还是要做的,比如接受我们客户的投诉和索赔要求,或者老板的出所筒。

     InputManager使用两个线程:

     1)InputReaderThread叫做"InputReader"线程,它负责读取并预处理RawEvent,applies policy并且把消息送入DispatcherThead管理的队列中。

     2)InputDispatcherThread叫做"InputDispatcher"线程,它在队列上等待新的输入事件,并且异步地把这些事件分发给应用程序。

     InputReaderThread类与InputDispatcherThread类不共享内部状态,所有的通信都是单向的,从InputReaderThread到InputDispatcherThread。两个类可以通过InputDispatchPolicy进行交互。

     InputManager类从不与Java交互,而InputDispatchPolicy负责执行所有与系统的外部交互,包括调用DVM业务。

3.2 创建流程

1)在android_server_InputManager_nativeInit中创建NativeInputManager对象,并保存到gNativeInputManager中;

2)在创建NativeInputManager对象时,它会创建EventHub对象<且创建是其成员mNeedToScanDevices的值为true>,然后把刚创建的EventHub对象作为参数创建InputManager对象;

3)在创建InputManager对象时,创建InputReader对象,然后把它作为参数创建InputReaderThread;创建InputDispatcher对象,然后把它作为参数创建InputDispatcherThread对象;(注:以上两个线程对象都有自己的threadLoop函数,它将在Thread::_threadLoop中被调用,这个Thread::_threadLoop是线程入口函数,线程在Thread::run中被真正地创建)

4.1)创建InputReader对象

4.1.1)把EventHub、readerPolicy<实质为NativeInputManager对象>和创建的InputDispatcher对象作为参数创建InputReader对象:mReader = new InputReader(eventHub, readerPolicy, mDispatcher);

4.1.2)在创建InputReader时, 保存EventHub对象到mEventHub中,并创建QueuedInputListener对象并保存在mQueuedListener中

4.2)创建InputDispatcher对象

4.2.1)把传入的参数dispatcherPolicy<实质为NativeInputManager对象>作为参数创建InputDispatcher对象:mDispatcher = new InputDispatcher(dispatcherPolicy);

4.2.1)在创建InputDispatcher时,创建了一个looper对象:mLooper = new Looper(false);

3.3 启动流程

1)在android_server_InputManager_nativeStart中调用InputManager::start,代码如下:

result = gNativeInputManager->getInputManager()->start();

2)在InputManager::start中,调用mDispatcherThread->run和mReaderThread->run,代码如下:

result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);

3)在上面的Thread::run中,调用createThreadEtc函数,并以Thread::_threadLoop作为入口函数,以上面的mDispatcherThread或mReaderThread作为userdata创建线程

4)至此InputReader线程和InputDispatcher线程都已经工作,详细信息见Thread::_threadLoop,在此函数中它将调用mDispatcherThread或mReaderThread的threadLoop函数来做真正的事

5.1)mReaderThread->threadLoop

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}

5.2)mDispatcherThread->threadLoop

bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;

 

3.4 EventInput对象关系图 

 

4. 设备操作流程

从EventHub::getEvents读取的事件数据结构如下:

struct RawEvent {
        nsecs_t when;        //事件发生的时间    int32_t deviceId;    //产生此事件的设备,比如发送FINISHED_DEVICE_SCAN,不需要填此项    int32_t type;        //事件类型(如:DEVICE_ADDED,DEVICE_REMOVED,FINISHED_DEVICE_SCAN)    int32_t scanCode;    int32_t keyCode;    int32_t value;    uint32_t flags;};

读取事件时的调用流程为:

Thread::_threadLoop->

     InputReaderThread::threadLoop->

          InputReader::loopOnce->

               EventHub::getEvents->

4.1 打开设备

      在EventHub::getEvents中,当mNeedToScanDevices为true时<当创建EventHub对象时,它就为true>,它将从/dev/input目录下查找所有设备,并进行打开,获取其相关属性,最后加入mDevices列表中。

EventHub::scanDevicesLocked->

     EventHub::scanDirLocked("/dev/input")->

         EventHub::openDeviceLocked

4.1.1 打开事件输入设备

     打开事件输入设备,在用户态调用open,则在kernel态中调用evdev_open函数,evdev_open处理流程如下:

     1)首先从参数inode中获取在evdev_table中的索引,从而获取对应的evdev对象

     2)创建evdev_client对象,创建此对象时同时为其buffer成员分配对应的内存

     3)把新创建evdev_client对象添加到client_list链表中

     4)把client保存在file的private_data中

     5)调用evdev_open_device->input_open_device->input_dev.open函数打开设备。

 

4.2 读取输入事件

      要说EventHub::getEvents如何获取输入事件,不得不先说说它的几个相关的成员变量:

     1)mPendingEventCount:调用epoll_wait时的返回值,当然如果没有事件,则其值为0;

     2)mPendingEventIndex:当前需要处理的事件索引

     3)mEpollFd:epoll实例,在EventHub::EventHub中初始化此例,所有输入事件通过epoll_wait来获取,每一个事件的数据结构为:struct epoll_event,为了搞明白如何读取输入事件的原理,不得不对epoll相关的东东搞个清清楚楚,明明白白,见epoll kernel实现原理。注:epoll_event只表明某个设备上有事件,并不包含事件内容,具体事件内容需要通过read来读取。

   struct epoll_event

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值