Android 源码分析系列综述博文: Android 系统源码分析综述
前言
Android/Linux 输入设备总类繁杂,常见的有按键、键盘、触摸屏、鼠标、摇杆等,之前其驱动都是采用字符设备、misc 设备处理的,但是如此多的设备就导致驱动混乱,所以 Linux 引入了输入子系统在字符设备等上抽象出一层来统一输入设备的驱动。本文就基于 MTK Android 7.0 源码来分析一下输入子系统。
输入子系统架构
输入子系统的系统架构如下图所示:
Framework 层以上只是简单跟了一下源码,没有深入查看
输入子系统分层解析
Hardware层
硬件层主要就是按键、触摸屏、Sensor等各种输入设备。
Kernel层
Kernel 层主要分为三层,如下:
- Input 设备驱动层: 采集输入设备的数据信息,通过 Input Core 的 API 上报数据。
- Input Core(核心层):为事件处理层和设备驱动层提供接口API。
- Event Handler(事件处理层):通过核心层的API获取输入事件上报的数据,定义API与应用层交互。
Kernel 层重要的数据结构如下:
数据结构 |
定义位置 |
简述 |
struct input_dev |
input.h |
Input 设备驱动中实例化 |
struct evdev struct mousedev struct keybdev |
evdev.c mousedev.c keybdev.c |
Event Handler 层逻辑 input 设备的数据结构 |
struct input_handler |
Input.h |
Event handler 的结构,handler 层实例化 |
Struct input_handle |
Input.h |
用于创建驱动层 input_dev 和 handler 链表的链表项结构 |
数据结构部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| # alps\kernel-3.18\include\linux\input.h
struct input_dev { const char *name; struct input_id id; unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; ... unsigned int keycodemax; unsigned int repeat_key;
int (*setkeycode)() int (*getkeycode)() ... unsigned long key[BITS_TO_LONGS(KEY_CNT)]; ... int (*open)() int (*flush)(); ... struct input_handle __rcu *grab; struct list_head h_list; struct list_head node; ... }
struct input_handler {
void *private;
void (*event)(); int (*connect)(); void (*disconnect)(); void (*start)();
const char *name;
const struct input_device_id *id_table;
struct list_head h_list; struct list_head node; };
struct input_handle {
int open; const char *name;
struct input_dev *dev; struct input_handler *handler;
struct list_head d_node; struct list_head h_node; };
# alps/kernel-3.18/include/uapi/linux/input.h
struct input_event { struct timeval time; __u16 type; __u16 code; __s32 value; };
|
这部分主要实现各种输入设备的自己硬件相关的驱动并上报事件,这部分驱动基本遵循如下流程:
- 声明实例化input_dev 对象
- 注册 input_dev
- input_allocate_device() 给设备分配空间,设置dev (实现于 input.c)
- 通过 input_register_device() 注册 (实现于 input.c)
- 硬件初始化,中断初始化,定义中断处理程序
- 设置input_dev对象
- 定义中断处理程序,上报事件
由于我自己有个外设系列源码分析,这里就不详细查看相关源码了,主要分析输入子系统的通用部分。设备驱动路径:
1
| alps\kernel-3.18\drivers\input
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| # alps\kernel-3.18\drivers\input\input.c input_init() class_register(&input_class); input_proc_init(); proc_mkdir("bus/input", NULL); proc_create("devices"..&input_devices_fileops); proc_create("handlers"..&input_handlers_fileops); register_chrdev_region(MKDEV(INPUT_MAJOR, 0),INPUT_MAX_CHAR_DEVICES, "input");
input_register_device() __set_bit(EV_SYN, dev->evbit); __clear_bit(KEY_RESERVED, dev->keybit); ... device_add(&dev->dev); list_add_tail(&dev->node, &input_dev_list); list_for_each_entry(handler, &input_handler_list, node) input_attach_handler(dev, handler); input_attach_handler() input_match_device(handler, dev) handler->connect(handler, dev, id); input_register_handler INIT_LIST_HEAD(&handler->h_list); list_add_tail(&handler->node, &input_handler_list); list_for_each_entry(dev, &input_dev_list, node) input_attach_handler(dev, handler); input_event() input_handle_event()/input_repeat_key() input_get_disposition input_pass_values() input_to_handler() handler->events() input_start_autorepeat() input_stop_autorepeat(dev) input_handle_abs_event() input_abs_set_val(dev, ABS_MT_SLOT, mt->slot) input_start_autorepeat()
input_inject_event() input_handle_event()
input_open_device handle->open++ dev->open(dev)
input_dev_suspend() ...
# alps\kernel-3.18\include\linux\input.h input_report_xx() input_event() input_sync input_event()
# alps\kernel-3.18\include\linux\input-polldev.h struct input_polled_dev
# alps\kernel-3.18\drivers\input\input-polldev.c input_register_polled_device() NIT_DELAYED_WORK(&dev->work, input_polled_device_work); input_open_polled_device() input_polldev_set_poll()
|
Event Handler
Event Handler 层以通用的 evdev.c 为例来解析,上层和 Kernel 层的交互在此文件完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| # alps\kernel-3.18\drivers\input\evdev.c static struct input_handler evdev_handler = { .event = evdev_event, .events = evdev_events, .connect = evdev_connect, .disconnect = evdev_disconnect, .legacy_minors = true, .minor = EVDEV_MINOR_BASE, .name = "evdev", .id_table = evdev_ids, }; truct file_operations evdev_fops = { .owner = THIS_MODULE, .read = evdev_read, .write = evdev_write, .poll = evdev_poll, .open = evdev_open, ... } struct evdev_client { unsigned int head; unsigned int tail; .... struct wake_lock wake_lock; struct list_head node; struct input_event buffer[]; };
evdev_init() input_register_handler(&evdev_handler) evdev_connect() struct evdev *evdev; dev_set_name(&evdev->dev, "event%d", dev_no); evdev->handle.dev = input_get_device(dev); evdev->handle.handler = handler; ... cdev_init(&evdev->cdev, &evdev_fops); device_add(&evdev->dev); evdev_event() evdev_events() evdev_pass_values() __pass_event() wake_up_interruptible(&evdev->wait) evdev_flush() input_flush_device() evdev_write() input_event_from_user() input_inject_event() evdev_read() # alps\kernel-3.18\drivers\input\input-compat.c input_event_from_user() copy_from_user() input_event_to_user()
|
Framework 层
Framework 层涉及面太广,内容也多,我现在阅读这部分上层源码也有些吃力,再加上时间原因,只简单跟读了几个关键文件。以后抽时间再跟读一下源码,产出一篇博客。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| # alps\frameworks\native\services\inputflinger # alps\frameworks\native\libs\input
# alps\frameworks\native\services\inputflinger\EventHub.cpp # alps\frameworks\native\services\inputflinger\InputManager.cpp
# alps\frameworks\native\services\inputflinger\InputReader.cpp
# alps\frameworks\native\services\inputflinger\InputDispatcher.cpp # alps\frameworks\native\services\inputflinger\InputListener.cpp
# alps\frameworks\base\services\core\java\com\android\server\input # alps\frameworks\base\services\core\java\com\android\server\wm
# alps\frameworks\base\services\core\java\com\android\server\input\InputManagerService.java # alps\frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
|
附 Shell 操作路径
在 Kernel 层生成三个路径及相关设备文件,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| event0 event11 event4 event7 input0 input11 input4 input7 event1 event2 event5 event8 input1 input2 input5 input8 event10 event3 event6 event9 input10 input3 input6 input9
event0 event10 event2 event4 event6 event8 event1 event11 event3 event5 event7 event9
devices handlers
I: Bus=0019 Vendor=0000 Product=0000 Version=0000 N: Name="ACCDET" P: Phys= S: Sysfs=/devices/virtual/input/input0 U: Uniq= H: Handlers=gpufreq_ib event0 B: PROP=0 B: EV=3 B: KEY=40 0 0 0 0 0 0 1000000000 c000001800000 0
...
I: Bus=0019 Vendor=0000 Product=0000 Version=0001 N: Name="fingerprint_key" P: Phys= S: Sysfs=/devices/virtual/input/input2 U: Uniq= H: Handlers=gpufreq_ib event2 B: PROP=0 B: EV=3 B: KEY=2000100000000000 180001f 8000000000000000
...
cat handlers // 查看注册的handler N: Number=0 Name=gpufreq_ib N: Number=1 Name=evdev Minor=64
|