Android 按键流程

一、驱动层流程

主要流程涉及以下文件

kernel/msm-4.19/drivers/input/keyboard/gpio_keys.c

kernel/msm-4.19/drivers/input/input.c

kernel/msm-4.19/drivers/input/evdev.c

kernel/msm-4.19/drivers/input/input-compat.c

有按键动作时,根据 dtsi 中配置 code 上报事件。在 gpio_keys.c 中进行处理,最终在 gpio_keys_gpio_report_event 函数中调用 input.c 上报事件。大概流程分为两步。

第一步:获取event事件保存到队列中

input.c:input_event -> input_handle_event -> input_pass_values -> input_to_handler(此函数中调用 handler->events ,handler 定义在 evdev.c 中,events 对应函数 evdev_events)

evdev.c:evdev_events -> evdev_pass_values -> __pass_event (将event事件添加到缓存队列 client->buffer)

第二步:通过循环读取队列中event事件保存到用户内存

evdev.c:evdev_read -> input_event_to_user

input-compat.c:input_event_to_user -> copy_to_user

 二、上层流程

主要流程涉及以下文件

frameworks/native/services/inputflinger/reader/EventHub.cpp

frameworks/native/services/inputflinger/reader/InputReader.cpp

frameworks/native/services/inputflinger/reader/InputDevice.cpp

frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

frameworks/native/libs/input/KeyLayoutMap.cpp

frameworks/native/libs/input/Keyboard.cpp

上层获取按键事件流程大致如下:

InputReader.cpp:loopOnce -> processEventsLocked -> processEventsForDeviceLocked (调用 device->process)

InputDevice.cpp:process (调用 mapper.process)

KeyboardInputMapper.cpp:process -> processKey(调用 getListener()->notifyKey)

InputDispatcher.cpp:notifyKey(调用 mPolicy->interceptKeyBeforeQueueing 传递到java层)

三、键值转换

按键键值有两个,底层驱动键值和上层应用使用键值,这个对应关系定义在 kl 文件中,kl 文件可以有多个,例如 Generic.kl fts_ts.kl 等,默认系统中路径在 /system/usr/keylayout/ 目录下。

#kl 文件内容格式
#key 驱动键值 上层键值
key 113   VOLUME_MUTE
key 114   VOLUME_DOWN
key 115   VOLUME_UP
key 116   POWER

系统开机时,会根据 frameworks/native/libs/input/InputDevice.cpp 规则加载 kl 文件。加载 kl 文件函数在 KeyLayoutMap.cpp 中,将所有文件按照 kl 名称类型加到 KeyedVector 中缓存。

KeyLayoutMap.cpp:load -> parse -> parseKey

//parseKey 代码段
KeyedVector& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;

... ...

#if DEBUG_PARSER
    ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
            mapUsage ? "usage" : "scan code", code, keyCode, flags);
#endif
    Key key;
    key.keyCode = keyCode;
    key.flags = flags;
    map.add(code, key);
    return NO_ERROR;

 parseKey 函数 KeyedVector map 中按照 code-key 格式保存,code就是 kl 中驱动键值,key里面保存了 kl 中上层键值。当驱动按键事件上来后,根据驱动键值查询上层键,整合再上传到java层供应用使用。查询动作在 KeyboardInputMapper.cpp processKey 函数中。函数调用关系如下:

[KeyboardInputMapper.cpp]processKey(getDeviceContext().mapKey) -> [InputDevice.h]mapKey -> [EventHub.cpp]mapKey -> [KeyLayoutMap.cpp]mapKey -> getKey

const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
    if (usageCode) {
        ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
        if (index >= 0) {
            return &mKeysByUsageCode.valueAt(index);
        }
    }
    if (scanCode) {
        ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
        if (index >= 0) {
            return &mKeysByScanCode.valueAt(index);
        }
    }
    return nullptr;
}

这里面的 mKeysByScanCode 就是上面解析 kl 保存的键值map,通过 scanCode(驱动键值)获取下标,通过下标获取 Key(上面说过的,保存上层键值的)。最后 KeyboardInputMapper.cpp processKey 后续流程把包含 Key 上报到 java 层使用。

你可能感兴趣的:(Android,android)