在之前按键过程分析的几篇博客中,我分析过关于按键kl文件的加载,但是讲的不是非常详细,这篇博客主要把kl文件加载过程单独拉出来分析下。
1. 获取InputDeviceIdentifier的name 以及 Device的创建
InputDeviceIdentifier的name 非常重要,后面寻找idc kl kcm文件都需要这个name。
我们看下面的调用流程EventHub::getEvents -> EventHub::scanDevicesLocked -> EventHub::scanDirLocked -> EventHub::openDeviceLocked
我们来看EventHub::openDeviceLocked函数,先是打开devicePath,然后利用ioctl获取InputDeviceIdentifier的name
status_t EventHub::openDeviceLocked(const char *devicePath) {
char buffer[80];
ALOGE("Opening device: %s", devicePath);
int fd = open(devicePath, O_RDWR | O_CLOEXEC);
if(fd < 0) {
ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
}
InputDeviceIdentifier identifier;
// Get device name.
if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name.setTo(buffer);
}
下面创建了Device,各种打印。
Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
ALOGW("add device %d: %s\n", deviceId, devicePath);
ALOGW(" bus: %04x\n"
" vendor %04x\n"
" product %04x\n"
" version %04x\n",
identifier.bus, identifier.vendor, identifier.product, identifier.version);
ALOGW(" name: \"%s\"\n", identifier.name.string());
ALOGW(" location: \"%s\"\n", identifier.location.string());
ALOGW(" unique id: \"%s\"\n", identifier.uniqueId.string());
ALOGW(" descriptor: \"%s\"\n", identifier.descriptor.string());
ALOGW(" driver: v%d.%d.%d\n",
driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
// Load the configuration file for the device.
loadConfigurationLocked(device);
先来看下打印
EventHub: Opening device: /dev/input/event4
EventHub: Created descriptor: raw=:0000:0000:name:comip_snd_soc Headset, cooked=2efc90e2a7d3beb2de2b795a507e8489f0acd57f
EventHub: add device 1: /dev/input/event4
EventHub: bus: 0000
EventHub: vendor 0000
EventHub: product 0000
EventHub: version 0000
EventHub: name: "comip_snd_soc Headset"
EventHub: location: "ALSA"
EventHub: unique id: ""
EventHub: descriptor: "2efc90e2a7d3beb2de2b795a507e8489f0acd57f"
EventHub: driver: v1.0.1
2. 加载idc文件
在我们的设备中,一般没有定义自己的idc文件,也就找不到。一般定义idc文件,是在这个文件中定义kl 和kcm文件。
我们再来分析下loadConfigurationLocked函数,调用getInputDeviceConfigurationFilePathByDeviceIdentifier函数,当configurationFile不为空的时候,调用PropertyMap::load加载idc文件,这部分代码是在system/libutil下面的,当有这个idc文件的时候,device->configuration就不为空。
void EventHub::loadConfigurationLocked(Device* device) {
device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
if (device->configurationFile.isEmpty()) {//configurationFile为空
ALOGD("No input device configuration file found for device '%s'.",
device->identifier.name.string());
} else {//如果有configurationFile文件,那我们就调用PropertyMap::load函数
ALOGD("input device configuration file name '%s'.",
device->configurationFile.string());
status_t status = PropertyMap::load(device->configurationFile,
&device->configuration);
if (status) {
ALOGE("Error loading input device configuration file for device '%s'. "
"Using default configuration.",
device->identifier.name.string());
}
}
}
调用了getInputDeviceConfigurationFilePathByDeviceIdentifier函数,其中type为0,代表是idc文件
String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
const InputDeviceIdentifier& deviceIdentifier,
InputDeviceConfigurationFileType type) {
if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {//不进入这个分支
if (deviceIdentifier.version != 0) {
// Try vendor product version.
String8 versionPath(getInputDeviceConfigurationFilePathByName(
String8::format("Vendor_%04x_Product_%04x_Version_%04x",
deviceIdentifier.vendor, deviceIdentifier.product,
deviceIdentifier.version),
type));
if (!versionPath.isEmpty()) {
return versionPath;
}
}
// Try vendor product.
String8 productPath(getInputDeviceConfigurationFilePathByName(
String8::format("Vendor_%04x_Product_%04x",
deviceIdentifier.vendor, deviceIdentifier.product),
type));
if (!productPath.isEmpty()) {
return productPath;
}
}
// Try device name.
return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
}
于是我们再来看getInputDeviceConfigurationFilePathByName函数:
String8 getInputDeviceConfigurationFilePathByName(
const String8& name, InputDeviceConfigurationFileType type) {
// Search system repository.
String8 path;
path.setTo(getenv("ANDROID_ROOT"));
path.append("/usr/");
appendInputDeviceConfigurationFileRelativePath(path, name, type);
ALOGD("Probing for system provided input device configuration file: path='%s'", path.s