AOSP15 Input专题getevent深入分析

5 阅读9分钟

在 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。

参数说明使用场景
-pPrint capabilities查看设备支持哪些事件(如是否支持多点触控、压力感应)。
-iGet ID info查看设备的 Vendor ID、Product ID,确认是否匹配了正确的 .idc 文件。
-lLabel output将十六进制代码转换为文字(如 EV_KEY),最常用。
-tTimestamp显示精确到微秒的时间戳,用于分析报点延迟。
-rRate显示实时报点频率(Hz),查看屏幕触控采样率。
-sSwitch 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