在 AOSP 15 中,getevent 是输入系统(Input System)调试的“第一现场”。它能够跳过复杂的 Android Framework 逻辑,直接读取 Linux 内核上报的原始事件(Raw Events)。
以下是对 AOSP 15 中 getevent 的源码深度解析、工作流程及常用命令指南。
一、 源码与编译逻辑分析
1. getevent是什么
在 AOSP 15 源码树中,getevent 的位置非常核心,它是 toolbox 工具集的一部分:
- 核心源码: system/core/toolbox/getevent.c
int getevent_main(int argc, char *argv[])
{
int c;
int i;
int res;
int get_time = 0;
int print_device = 0;
char *newline = "\n";
uint16_t get_switch = 0;
struct input_event event;
int print_flags = 0;
int print_flags_set = 0;
int dont_block = -1;
int event_count = 0;
int sync_rate = 0;
int64_t last_sync_time = 0;
const char *device = NULL;
const char *device_path = "/dev/input";
/* disable buffering on stdout */
setbuf(stdout, NULL);
opterr = 0;
do {
// 解析命令
c = getopt(argc, argv, "tns:Sv::dpilqc:rh");
if (c == EOF)
break;
switch (c) {
case 't':
get_time = 1;
break;
case 'n':
newline = "";
break;
case 's':
get_switch = strtoul(optarg, NULL, 0);
if(dont_block == -1)
dont_block = 1;
break;
case 'S':
get_switch = ~0;
if(dont_block == -1)
dont_block = 1;
break;
case 'v':
if(optarg)
print_flags |= strtoul(optarg, NULL, 0);
else
print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION;
print_flags_set = 1;
break;
case 'd':
print_flags |= PRINT_HID_DESCRIPTOR;
break;
case 'p':
print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE
| PRINT_DEVICE_NAME | PRINT_POSSIBLE_EVENTS | PRINT_INPUT_PROPS;
print_flags_set = 1;
if(dont_block == -1)
dont_block = 1;
break;
case 'i':
print_flags |= PRINT_ALL_INFO;
print_flags_set = 1;
if(dont_block == -1)
dont_block = 1;
break;
case 'l':
print_flags |= PRINT_LABELS;
break;
case 'q':
print_flags_set = 1;
break;
case 'c':
event_count = atoi(optarg);
dont_block = 0;
break;
case 'r':
sync_rate = 1;
break;
case '?':
fprintf(stderr, "%s: invalid option -%c\n",
argv[0], optopt);
case 'h':
usage(argv[0]);
exit(1);
}
} while (1);
if(dont_block == -1)
dont_block = 0;
if (optind + 1 == argc) {
device = argv[optind];
optind++;
}
if (optind != argc) {
usage(argv[0]);
exit(1);
}
//初始化 poll 结构
nfds = 1;
ufds = calloc(1, sizeof(ufds[0]));
// 监听 /dev/input 目录变化(插拔设备)
ufds[0].fd = inotify_init();
ufds[0].events = POLLIN;
if(device) {
if(!print_flags_set)
print_flags |= PRINT_DEVICE_ERRORS;
// 打开设备
res = open_device(device, print_flags);
// 打开失败
if(res < 0) {
return 1;
}
} else {
if(!print_flags_set)
print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
print_device = 1;
// 加入第一个目录到fd
res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
if(res < 0) {
fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno));
return 1;
}
// 扫描监听加入fd
res = scan_dir(device_path, print_flags);
if(res < 0) {
fprintf(stderr, "scan dir failed for %s\n", device_path);
return 1;
}
}
// 设备状态
if(get_switch) {
for(i = 1; i < nfds; i++) {
uint16_t sw;
res = ioctl(ufds[i].fd, EVIOCGSW(1), &sw);
if(res < 0) {
fprintf(stderr, "could not get switch state, %s\n", strerror(errno));
return 1;
}
sw &= get_switch;
printf("%04x%s", sw, newline);
}
}
if(dont_block)
return 0;
while(1) {
//int pollres =
poll(ufds, nfds, -1);
// 监听 /dev/input 目录变化(插拔设备)
if(ufds[0].revents & POLLIN) {
read_notify(device_path, ufds[0].fd, print_flags);
}
// ufds[1..n] = input 设备 fd
for(i = 1; i < nfds; i++) {
if(ufds[i].revents) {
if(ufds[i].revents & POLLIN) {
res = read(ufds[i].fd, &event, sizeof(event));
if(res < (int)sizeof(event)) {
fprintf(stderr, "could not get evdev event, %s\n", strerror(errno));
return 1;
}
if(get_time) {
printf("[%8ld.%06ld] ", event.time.tv_sec, event.time.tv_usec);
}
if(print_device)
printf("%s: ", device_names[i]);
print_event(event.type, event.code, event.value, print_flags);
if(sync_rate && event.type == 0 && event.code == 0) {
int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
if(last_sync_time)
printf(" rate %lld", 1000000LL / (now - last_sync_time));
last_sync_time = now;
}
printf("%s", newline);
if(event_count && --event_count == 0)
return 0;
}
}
}
}
return 0;
}
- 二进制路径: /system/bin/getevent
- 依赖头文件: bionic/libc/kernel/uapi/linux/input.h (定义了输入协议的数据结构,如 input_event)
// linux/input.h
struct input_event {
struct timeval time; // 时间戳
__u16 type; // 事件类型 (如 EV_KEY, EV_ABS)
__u16 code; // 事件代码 (如 BTN_TOUCH, ABS_MT_POSITION_X)
__s32 value; // 事件值 (如 1 为按下, 0 为抬起, 或坐标值)
};
2、核心代码逻辑分析
getevent 的实现本质上是一个 多路复用(I/O Multiplexing) 的监听器。
Step 1: 扫描设备节点
程序启动后,会遍历 /dev/input/ 目录。通过 scandir 获取所有 eventX 节点。
static int scan_dir(const char *dirname, int print_flags)
{
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
if(dir == NULL)
return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while((de = readdir(dir))) {
if(de->d_name[0] == '.' &&
(de->d_name[1] == '\0' ||
(de->d_name[1] == '.' && de->d_name[2] == '\0')))
continue;
strcpy(filename, de->d_name);
// 加入nfds监听
open_device(devname, print_flags);
}
closedir(dir);
return 0;
}
Step 2: 轮询监听 (Poll)
int getevent_main(int argc, char *argv[])
{
// ...
while(1) {
// poll 轮询监听,阻塞等待,直到有硬件输入
poll(ufds, nfds, -1);
if(ufds[0].revents & POLLIN) {
read_notify(device_path, ufds[0].fd, print_flags);
}
for(i = 1; i < nfds; i++) {
if(ufds[i].revents) {
if(ufds[i].revents & POLLIN) {
res = read(ufds[i].fd, &event, sizeof(event));
// ...
// 格式化输出到控制台
print_event(event.type, event.code, event.value, print_flags);
// ...
}
}
}
}
return 0;
}
Step 3: 数据解析
它读取的是内核定义的 struct input_event。如果是带有 -l 参数,它会查询内置的字符串表,将 0003 0035 这种十六进制转换为人类可读的 EV_ABS ABS_MT_POSITION_X。
3. 常用命令
在终端(adb shell)中,getevent 提供了丰富的参数来过滤和展示数据,用比较多的命令 -lrt。
| 参数 | 说明 | 使用场景 |
|---|---|---|
| -p | Print capabilities | 查看设备支持哪些事件(如是否支持多点触控、压力感应)。 |
| -i | Get ID info | 查看设备的 Vendor ID、Product ID,确认是否匹配了正确的 .idc 文件。 |
| -l | Label output | 将十六进制代码转换为文字(如 EV_KEY),最常用。 |
| -t | Timestamp | 显示精确到微秒的时间戳,用于分析报点延迟。 |
| -r | Rate | 显示实时报点频率(Hz),查看屏幕触控采样率。 |
| -s | Switch status | 查看开关状态(如盖合传感器、耳机孔插拔状态)。 |
二、协议指令分析和实战
1、类型
1.1 EV_SYN
同步事件完,在事件开始或完成会有,对应的code:
- 0004:代表一个事件开始(不必要)
- 0005:代表一个事件开始(不必要)
- SYN_REPORT:代表一个事件的结束 (必要)
1.2 EV_ABS
事件的一种绝对坐标类型,对应code:
- ABS_MT_SLOT: 本质代表者不同手指,它的value代表手指id
- ABS_MT_TRACKING_ID: 类型B特有的,实际上,每个slot会和一个ID相对应,一个非负数的表示一次接触,-1表示这是一个无用的slot(或者理解为一次接触的结束) 。无论在接触的类型相对应的slot发生了改变,驱动都应该通过改变这个值来使这个slot失效。并且下一次触摸的ID值会是这次的值加1。
- ABS_MT_POSITION_X,ABS_MT_POSITION_Y: 相对于屏幕中心的x,y坐标。
- ABS_MT_TOUCH_MAJOR: 接触部分的长轴长度。相当于椭圆的长轴。
- ABS_MT_TOUCH_MINOR: 接触部分的短轴长度。相当于椭圆的短轴。
- ABS_MT_PRESSURE: 代表按下压力,有的设备不一定有
1.3 EV_KEY
事件的一种类型。表示是按键(不仅仅指的物理按键也包括TOUCH)事件,对应code:
- BTN_TOUCH: 触碰按键。其值是DOWN或者UP。
- BTN_TOOL_FINGER: 按键的是finger,并且其值也是DOWN或者UP
2、案例分析, 因为模拟器问题,实践设备没办法
add device 1: /dev/input/event3
name: "ilitek_ts"
add device 2: /dev/input/event2
name: "Newland Auto-ID NLS IOTC PRDs HID KBW"
add device 3: /dev/input/event1
name: "rk29-keypad"
add device 4: /dev/input/event0
name: "rk_headset"
[ 1021.576809] /dev/input/event3: EV_KEY BTN_TOUCH DOWN
[ 1021.576809] /dev/input/event3: EV_ABS ABS_MT_TRACKING_ID 00000007 第一个手指对应的TRACKING_ID
[ 1021.576809] /dev/input/event3: EV_ABS ABS_MT_POSITION_X 00001416 按下X轴坐标
[ 1021.576809] /dev/input/event3: EV_ABS ABS_MT_POSITION_Y 000009f3 按下Y轴坐标
[ 1021.576809] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000080 按下的椭圆长轴
[ 1021.576809] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000001 按下的椭圆长轴
[ 1021.576809] /dev/input/event3: EV_SYN SYN_REPORT 00000000 --同步尾(不省略)
.....
[ 1021.601178] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000001 代表第二手指出来了
[ 1021.601178] /dev/input/event3: EV_ABS ABS_MT_TRACKING_ID 00000008 第二个手指对应的TRACKING_ID
[ 1021.601178] /dev/input/event3: EV_ABS ABS_MT_POSITION_X 000010a1 第二手指坐标
[ 1021.601178] /dev/input/event3: EV_ABS ABS_MT_POSITION_Y 0000164c 第二手指坐标
[ 1021.601178] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000080
[ 1021.601178] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000001
[ 1021.601178] /dev/input/event3: EV_SYN SYN_REPORT 00000000
[ 1021.611940] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000000 第一手指
[ 1021.611940] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000080
[ 1021.611940] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000001
[ 1021.611940] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000001
[ 1021.611940] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000080
[ 1021.611940] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000001
[ 1021.611940] /dev/input/event3: EV_SYN SYN_REPORT 00000000
[ 1021.622700] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000000 第一手指
[ 1021.622700] /dev/input/event3: EV_ABS ABS_MT_POSITION_X 0000141f 第一手指坐标
[ 1021.622700] /dev/input/event3: EV_ABS ABS_MT_POSITION_Y 00000a08 第一手指坐标
[ 1021.622700] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000080
[ 1021.622700] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000001
[ 1021.622700] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000001 第二手指
[ 1021.622700] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000080 第二手指坐标
[ 1021.622700] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000001 第二手指坐标
[ 1021.622700] /dev/input/event3: EV_SYN SYN_REPORT 00000000
[ 1021.668726] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000000
[ 1021.668726] /dev/input/event3: EV_ABS ABS_MT_POSITION_X 0000155e
[ 1021.668726] /dev/input/event3: EV_ABS ABS_MT_POSITION_Y 00000d33
[ 1021.668726] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000080
[ 1021.668726] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000001
[ 1021.668726] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000001
[ 1021.668726] /dev/input/event3: EV_ABS ABS_MT_POSITION_X 000010f7
[ 1021.668726] /dev/input/event3: EV_ABS ABS_MT_POSITION_Y 00001713
[ 1021.668726] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000080
[ 1021.668726] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000001
[ 1021.668726] /dev/input/event3: EV_SYN SYN_REPORT 00000000
[ 1021.679451] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000000
[ 1021.679451] /dev/input/event3: EV_ABS ABS_MT_POSITION_X 0000160a
[ 1021.679451] /dev/input/event3: EV_ABS ABS_MT_POSITION_Y 00000ef2
[ 1021.679451] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000080
[ 1021.679451] /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 00000001
[ 1021.679451] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000001
[ 1021.679451] /dev/input/event3: EV_ABS ABS_MT_TRACKING_ID ffffffff 第二个手指消失抬起
[ 1021.679451] /dev/input/event3: EV_SYN SYN_REPORT 00000000
[ 1021.690232] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000000
[ 1021.690232] /dev/input/event3: EV_ABS ABS_MT_TRACKING_ID ffffffff 第一个手指消失抬起
[ 1021.690232] /dev/input/event3: EV_KEY BTN_TOUCH UP
[ 1021.690232] /dev/input/event3: EV_SYN SYN_REPORT 00000000