目录
1 Android输入系统
Android输入系统涉及到驱动,HAL|C 及Framework层,这里聚焦于驱动与本地执行层间的交互。其架构参考如下
1.1 Android Input核心交互
如上图,本篇分析聚焦于Native层与Kernel交互,帮助梳理c/c++层模拟按键技术支持。这里分为两个部分,文件节点读写及节点传输协议解析
1.1.1 文件节点读写
这里来分析下Android系统针对输入设备的读写逻辑,先来看下驱动写输入事件到文件节点
定位文件到drivers/input/input.c,这是Android input子系统核心实现
subsys_initcall(input_init);
module_exit(input_exit);
这里可以看到,input是内核加载即加载的核心驱动,下面来看下其引导函数
很明显,这里主要做了几件事,在sys文件系统及proc文件系统建立对应目录,申请字符设备号等。这块涉及到input子系统初始化,不展开。这里关注驱动写事件到文件节点(文件节点在对应的设备注册时创建)。
一般的设备中断时,从其寄存器读取事件通过input系统input_report_abs函数上传,如下
其在input.h中以inline实现,下面来看下input_event函数
这里通过自旋锁禁用本地中断,完成一次中断处理(此时处于中断上下文),在调用input_handle_event数据前,通过is_event_supported来查看硬件设备支持的事件类型,在adb中可以通过命令getevent –p查看,编者的amlogic平台如下:
下面来看input_handle_event函数
这里首先获取对此事件的处理策略,再处理,这里简单来看下此函数
可以看到对tpye=ev_syn的事件,其处理flag为INPUT_PASS_TO_HANDLERS | INPUT_FLUSH,同理查看ev_rel的处理flag为INPUT_PASS_TO_HANDLERS
此时回到input_handle_event函数,来分析
这里有个重点,就是普通的事件上报,在第一步完成后,面临两个策略:
1 如果flag中有inpu_flush,则完成此事件上报
2 如果flag中午inpu_flush,但vals数组个数如果是max-1,则也需要分段上报。这里假设满足上面中的任何一条件,继续来看
这里首先通过rcu_read_lock(),进入读端临界区读取变量,之后通过input_to_handler来处理事件。这里先不关注重复事件处理,接着来看input_to_handler
这个函数,整体逻辑就是先filter事件,对于有效事件再通过handle来传递。
这里需要注意下,输入事件过滤的连续性,否则for循环处理逻辑就有问题
这里调用handler->events函数处理,这里需要说明下,此函数指针注册在evdec.c中,这里简单提一下,可深入如下:
接上文,这里来分析evdev-event函数,其内部又调用evdev-events函数,展开来看
这里可以看到数据通过数组指针传递到evdev子系统,待其处理,接下来看下evdev是如何处理这一组输入事件的
如注释,这里主要分为两步,即是组装事件到evdev的buffer中,第二部通知唤醒
先来看下如何组装批量数据
这里主要是把数据放入client->buffer。(kill_fasync异步通知机制这里暂不涉及)
接上文在组装完事件数据后,通过wake_up_interruptible通知唤醒到注册在等待队列上的进程。该函数不能直接的立即唤醒进程,而是由调度程序转换上下文,调整为可运行状态。在这个语境下次进程就是当前进程,由于内核写文件节点逻辑处于中断上下文,猜测应该在进程上下文进程因为一些条件阻塞在此等待队列中,此时就被唤醒了,来处理evdev_client中的buffer数组了。简单参考如下(evdev_read函数):
1.1.2 Framework层抓取事件
下个阶段来简单分析下输入事件的读取,基于input系统框架图,完成事件