打印
[资料分享]

安卓底层开发学习经验第二十九期

[复制链接]
864|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
上一期我们学习了Android Input系统的framework层所涉及到的几个类,InputManagerInputReaderEventHub以及InputDispatcher下面我们来分析一下EventHub
EventHub所做的主要工作就是来监听底层的输入事件,监听的是/dev/input目录,他首先会把这个目录下的所有设备打开,然后拿到相应的属性,创建相应的设备,再去轮巡下面的设备,读取设备的消息,然后通过消息向上返,这样系统就能拿到具体硬件设备所发出来的消息,另外他还要监听我们的热插拔设备,比如我们有蓝牙的键鼠,或者其他设备,能够支持USB鼠标键盘的话,插上后可以识别我们的设备。如果我们插上一个设备,那么他就会监听我们的dev/input目录,如果有消息表示添加了一个设备,那么就会打开这个设备,并且把它添加到我们监听的设备列表中,然后去监听设备的输入事件。如果设备拔下之后还会做一个remove的操作,将这个设备关闭移除。我们会根据设置的一些名字类型,和我们Android系统的一些配置文件,以及键值的映射文件,对底层的键值进行一个映射。比如我们添加了一个power键,对于上层应用来说power键只有一个值,但是对于我们底层来说,返回的值可能是不一样的,这个时候我们就可以用配置文件来做一个键值的映射。比如我们不同的设备返回的值是1,那么对应上层power键的值可能是2,那么这时候会做一个映射,换到另一个硬件系统中,power键返回的值是2,对于我们上层来说还是2,这时候我们也做一个映射,换成第三个设备,如果power值是3,上层对应的值是2,那么32就坐一个映射,而且还要做一些软键盘的映射这就是EventHub所做的工作。第四个就是将我们dev目录下发现的所有设备,添加到我们本地的列表中,对他进行循环的监听,如果说我们InputReader这个Thread开始轮巡我们消息,那么轮训一次我们EventHub做一次轮巡,做一次轮巡之后返给我们的InputReader,也就是第五条,我们要捕获事件,捕获事件的主动发起者是我们的上层应用,如果有一个应用已经打开了,这时候我们肯定会监听我们的touch事件,或者如果我们有一个Input的输入框,这时候我们也会监听软键盘的事件,都是输入事件,而且他随时都要监听我们的power消息,和音量加减,媒体的消息,这些消息打开之后都是我们的EventHub来捕获的,发起者就是我们的上层应用。下面我们再来看一下EventHubInputReader处理不同输入设备的一个过程
首先我们要知道Android所支持输入设备的类型,基本上就是按键、手柄以及触摸,触摸还会分为单点和多点,power键和音量加减都可以认为是按键消息,或者是键盘也可以理解为按键消息,如果我们想要在电视上玩手柄,那么我们就必须加上底层的驱动,然后才能报上相应的事件,而且手柄的驱动键值一般都是标准的,如果想要做兼容,那么在驱动上必须支持这个手柄。触摸我们可以做一个双点的自动缩放,这个是我们驱动所要支持的,如果驱动不支持多点触控,那么是不能够有这个多点输入的设备的。第二个是根据设备的类型和系统prop的消息,做一个键盘的布局,和一些键值的映射。第三会将我们的设备添加到InputReader中,EventHub所得到的设备都会添加到InputReader中。InputReader会根据设备的类型添加一个mapper,这个设备所做出来的消息,InputReader还要做一层过滤,做一层转换,然后才会把消息返回到上面。我们上面开始轮巡的话,InputReader做一次案件的收集,EventHub就会捕获一次,如果有按键值上来,或者触摸屏事件上来的话,EventHub不惑之后就会对按键进行处理,就是把按键值发送给InputReader,而InputReader会将按键值再做一次处理,处理完之后发送给分发的那个线程,分发的线程在发送给上层。线面我们再来看一下InputReader所涉及到的几个mapper
首先来看我们的inputReader,在这里面会有inputdevices,这就是我们EventHub扫描出来的设备,我们每一个devices都对应着一个mapper,我们mapper的类型分为键盘、鼠标、触摸屏事件,以及游戏手柄事件,比如我们捕获了一个消息,我们首先要调用process来进行一下处理,而我们真正的处理其实是根据InputMapper做的一个处理,实际按键的消息都在我们的每一个mapper中做处理,处理完之后才会发送给我们的Dispatcher这个线程,然后这个线程才会把消息向上分发,这样就知道了在我们InputReader中又多了这么几个类和对象,有我们的InputDeviceInputMapper,它对应着图片上边四个具体的对象,下面我们看一下代码EventHub具体实现,首先打开framework/base/services/input/EventHub.cpp
首先是create了一个mEpollFd,这个pollFd是使用的Poll的方式去轮巡我们的文件描述符。在下面又创建了一个inotifyinotify_add_watch所监听的路径是DEVICE_PATH,这个DEVICE_PATH就是我们的dev/input,也就是说如果我们的dev/input这个目录有增加或者减少一个设备的话,那么我们就可以监听到,而我们在监听的时候,会把mINotifyFd添加到mEpollFd中,添加的类型就是EPOLLIN,这样的话就可以实时的去监控我们热插拔的设备。在后边还创建了一对管道,这个管道是用于唤醒的,也把它添加到了EpollFd中。当我们这个初始化完成之后,这个dev/input就初始化完成了,那么他的设备具体是在那里打开的呢。其实是在我们loop的时候,在getEvents里面做的。如果需要ScanDevice的话,那么他会调用一个scanDevicesLocked()的一个方法,去获取我们Input目录下的所有设备。我们来看一下scanDirLocked所做的事情
他就是打开这个目录名,然后把这个目录下的所有设备添加到我们的一个字符串中,然后再去逐个的打开我们的设备,调用的就是openDeviceLocked(),这个函数就是打开具体的设备,是以读写的方式打开的,然后会得到我们设备的具体信息。我们切到具体设备中来看一下,打开我们的adb,登陆shell,然后cd proc cd bus ,层的input cat devices
这就是我们当前开发板中所支持的输入设备的类型,我们可以看到bus0019Vendor0001Product0001Version0100。上边还有一个handlers,对应的一个是我们的名字,一个是在dev目录下对应的具体设备。这就是我们底层对应的一些具体信息,当然还有一些信息我们只有在驱动中才能看到。
我们可以通过ioctl的操作把我们底层设备的信息全部拿到,拿到之后会设置他的描述文件,这个描述文件是和配置文件相关的一些设置。然后new一个Device,这个Device会保存在一个列表中,再往下他会load这个ConfigurationLocked,然后做一些ioctl的一些操作,把这些初始化都完成之后,会定义我们设备classes的类型。当我们这些设置完成之后他就会loadKeyMapLocked,这个load的过程就是和我们Android系统的映射文件对应起来。我们来找一个IDC文件来看一下,find out/target/product/fiber-a31st/ -name *idc   找到以后我们随便打开一个,我们现在来看一下out/target/product/fiber-a31st/system/usr/idc/qwerty.idc
这个是我们触摸屏的一个描述,触摸屏的keyboard.layout对应的是qwerty文件,map也是这个qwerty,我们找到这个文件来看一下这个qwerty
Find out/target/product/fiber-a31st/ -name qwerty* 里面有一个kl和一个kcm文件,我们首先来看一下kl文件
在这里会看到一个键值,我们可以看到每一个键对应的是什么,他都会在这里做一个映射,然后我们再来看一下kcm,他在这里也是一个映射,如果没有kl,那么他就会找kcm。当把这些都映射完之后,我们知道了我们底层的值和我们Android系统的值是如何来对起来的。
在这里他会将我们打开的设备名添加到mEpollFd中,这样我们就能监听我们这个设备,有消息的话,我们就能收到这个设备的消息,然后返给上层,再往下我们会将他添加到设备列表中。这就是EventHub所做的事情。那么我们再来看一下getEvents真正做的事情是什么。当我们初始化完成之后,就会调用mEpollFd的消息,获取我们真正的设备的值,如果我们这个设备真有的话他就会读取设备的值
拿到事件之后就会返回,而这个getEvents它所返回的值会添加到RawEvent* buffer这个对象中,那么这个buffer值就是InputReader所要传下来的变量,这个变量就会给了event buffer,这样就拿到了event的值,这就是EventHub所做的事情。我们对EventHub的分析就讲到这里。

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

102

主题

315

帖子

16

粉丝