Android5.0キーklファイルロードプロセス分析
50852 ワード
以前のキープロセス分析のいくつかのブログでは、キーklファイルのロードについて分析したことがありますが、非常に詳細ではありません.このブログは主にklファイルのロードプロセスを単独で分析しています. InputDeviceIdentifierのnameとDeviceの作成InputDeviceIdentifierのnameを取得することは非常に重要であり、後でidc kl kcmファイルを探すにはこのnameが必要である.次の呼び出しプロセスEventHub::getEvents->EventHub::scanDevicesLocked->EventHub::scanDirLocked->EventHub::openDeviceLocked EventHub::openDeviceLocked関数を見てみましょう.まずdevicePathを開き、ioctlを使用してInputDeviceIdentifierのname を取得します.
以下にデバイスを作成し、各種印刷を行います.//Load the configuration file for the device. loadConfigurationLocked(device); まず印刷を見てみましょうはidcファイルをロードします.私たちのデバイスでは、一般的に自分のidcファイルを定義していないので、見つかりません.一般的にidcファイルを定義し、このファイルでklとkcmファイルを定義します.さらに、loadConfigurationLocked関数を解析し、g e t i n p u t D i c e C o n f i g u r ationFilePathByDeviceIdentifiier関数を呼び出し、configurationFileが空でない場合、PropertyMap::loadを呼び出してidcファイルをロードします.このコードはsystem/libutilの下にあり、このidcファイルがある場合、device->configurationは空ではありません.
次に、g e t I n p u t D e v e c e C o n f i g u rationFilePathByName関数を見てみましょう.
この関数は、一致するidcファイルを探して、最後に見つからずに空のStringを返します.A p p p e n d I n p u t D e v i c e C o f i g u rationFileRelativePath関数を見てみましょう
この関数は、伝達されたパスと名前でidcファイルを構成します.次にg e t I n p u t D i c e C o n f i g u rationFilePathByNameファイルでappendInputDevice C o f i g u rationFileRelativePathファイルからなるidcファイルがあるかどうかを見て、あればidcを返すファイルパスを見つけて、最後に空のstringを返さなければなりません.私たちのこのロゴを見てみましょう.
私たちは私たちの携帯電話のidcディレクトリを見て、すべてオリジナルで、つまりframework/base/dataの下のファイルで、すべてオリジナルで、一致するidcファイルが見つからないに違いありません.idcファイルにこのkl kcmファイルの名前を保存します.次はidcファイル、次はその内容です.keyboard.Layoutはklのファイル名、keyboardを表します.characterMapはkcmのファイル名を表します. klファイルをロードklとkcmファイルをロードするのはopenDeviceLocked関数でloadKeyMapLocked関数を呼び出して完了します.では、openDeviceLocked関数を分析し続けます.klファイルをロードするコードについて:
loadKeyMapLocked関数
load関数を見てみましょう.前のidcファイルは一致していません.そのため、最初のブランチは直接スキップすることができ、probeKeyMap関数を直接見ることができます.
3.1 InputDeviceIdentifierのnameに一致するklファイルが見つかりません.オリジナルのGenericを使用します.klファイルの1つ目は、InputDeviceIdentifierのnameに一致するklファイルが見つからないことです.この場合、Generalを使用します.klファイルの代わりに.次にprobeKeyMap関数を直接見てみましょう.
まずisComplete関数を見てみましょう.klファイルとkcmファイルがあってからtrueを返します.load関数を見てください.isCompleteがtrueを返すと、klとkcmファイルが見つかったので、直接returnします.
次にklファイルをロードするプロセスを見てみましょう.kcmファイルのロードプロセスはklと似ています.私たちは見ません.
まずgetPath関数を見てみると、load関数でloadKeyLayoutを呼び出した最初のnameは空なので、ここではg e t I n p u t D e v e C o n f i g u rationFilePathByDeviceIdentifiier関数を使用します.
g e t I n p u t D i c e C o n f i g u r a t i o n F i l e PathByDeviceIdentifiier関数を見てみると、最初の部分は各種Vendorのようなklで、私たちはこの分岐に入っていません.
以前私たちのロゴでは、このnameがcomipです.snd_soc Headsetも、見つからなかった.
デバイスにどのklファイルがあるか見てみましょう.確かにcomipがありません.snd_soc Headsetというファイル.
振り返ってみるとload関数が呼び出した2番目のprobeKeyMap関数はGenericパラメータに渡されたもので、
probeKeyMap関数を見てみましょうか、loadKeyLayout関数を呼び出しましたか.
同様にgetPath関数を見てみましょう.このときnameは空ではありません.getInputDeviceConfigurationFilePathByName関数を呼び出します.
G e t I n p u t D i c e C o n f i g u rationFilePathByName関数は、最後にこの関数でGenericを見つけた.klファイル.
klファイルを見つけたら、このファイルをload関数で解析します.これは分析しません.スキャンコードをキーコードに変換するなどです.
上の例はGenericがロードする.klファイルは、system/usr/keylayoutの下に適切なものが見つからないためです.
3.2 InputDeviceIdentifierに一致するnameを見つけたklファイルの次の例は適切なklファイルを見つけたもので、logを見てみましょう.nameはft 5 x 06であることに注意してください.
デバイスのklファイルを見てみましょう.ft 5 x 06があります.klファイル、これで一致するklファイルが見つかり、元のGenericではありません.klです. klファイルを使用して、スキャンコードをキーコードに変換します.以前はキーフロー(一)で、キーを最後に各InputMapperのprocess関数で処理することを説明しました.次に、この関数を見て、EventHubのmapKeyを呼び出してスキャンコードをキーコードに変換します.
詳しくkcmのmapKeyとklのmapKeyを分析して後で分析しました
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
", 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
", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name.setTo(buffer);
}
以下にデバイスを作成し、各種印刷を行います.//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
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
[cpp] view plain copy
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);
}
次に、g e t I n p u t D e v e c e C o n f i g u rationFilePathByName関数を見てみましょう.
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.string());
if (!access(path.string(), R_OK)) {
ALOGD("Found");
return path;
}
// Search user repository.
// TODO Should only look here if not in safe mode.
path.setTo(getenv("ANDROID_DATA"));
path.append("/system/devices/");
appendInputDeviceConfigurationFileRelativePath(path, name, type);
ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
if (!access(path.string(), R_OK)) {
ALOGD("Found");
return path;
}
// Not found.
ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
name.string(), type);
return String8();
}
この関数は、一致するidcファイルを探して、最後に見つからずに空のStringを返します.A p p p e n d I n p u t D e v i c e C o f i g u rationFileRelativePath関数を見てみましょう
static void appendInputDeviceConfigurationFileRelativePath(String8& path,
const String8& name, InputDeviceConfigurationFileType type) {
path.append(CONFIGURATION_FILE_DIR[type]);
for (size_t i = 0; i < name.length(); i++) {
char ch = name[i];
if (!isValidNameChar(ch)) {
ch = '_';
}
path.append(&ch, 1);
}
path.append(CONFIGURATION_FILE_EXTENSION[type]);
}
static const char* CONFIGURATION_FILE_DIR[] = {
"idc/",
"keylayout/",
"keychars/",
};
static const char* CONFIGURATION_FILE_EXTENSION[] = {
".idc",
".kl",
".kcm",
};
この関数は、伝達されたパスと名前でidcファイルを構成します.次にg e t I n p u t D i c e C o n f i g u rationFilePathByNameファイルでappendInputDevice C o f i g u rationFileRelativePathファイルからなるidcファイルがあるかどうかを見て、あればidcを返すファイルパスを見つけて、最後に空のstringを返さなければなりません.私たちのこのロゴを見てみましょう.
InputDevice: Probing for system provided input device configuration file: path='/system/usr/idc/comip_snd_soc_Headset.idc'
InputDevice: Probing for system user input device configuration file: path='/data/system/devices/idc/comip_snd_soc_Headset.idc'
InputDevice: Probe failed to find input device configuration file: name='comip_snd_soc Headset', type=0
EventHub: No input device configuration file found for device 'comip_snd_soc Headset'.
log idc 。
[plain] view plain copy
root@lte26007:/system/usr/idc # ls
AVRCP.idc
qwerty.idc
qwerty2.idc
私たちは私たちの携帯電話のidcディレクトリを見て、すべてオリジナルで、つまりframework/base/dataの下のファイルで、すべてオリジナルで、一致するidcファイルが見つからないに違いありません.idcファイルにこのkl kcmファイルの名前を保存します.次はidcファイル、次はその内容です.keyboard.Layoutはklのファイル名、keyboardを表します.characterMapはkcmのファイル名を表します.
touch.deviceType = touchScreen
touch.orientationAware = 1
keyboard.layout = qwerty
keyboard.characterMap = qwerty
keyboard.orientationAware = 1
keyboard.builtIn = 1
cursor.mode = navigation
cursor.orientationAware = 1
status_t keyMapStatus = NAME_NOT_FOUND;
if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
// Load the keymap for the device.
keyMapStatus = loadKeyMapLocked(device);
}
loadKeyMapLocked関数
status_t EventHub::loadKeyMapLocked(Device* device) {
return device->keyMap.load(device->identifier, device->configuration);
}
load関数を見てみましょう.前のidcファイルは一致していません.そのため、最初のブランチは直接スキップすることができ、probeKeyMap関数を直接見ることができます.
status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
const PropertyMap* deviceConfiguration) {
// Use the configured key layout if available.
if (deviceConfiguration) {
String8 keyLayoutName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
keyLayoutName)) {
status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
"it was not found.",
deviceIdenfifier.name.string(), keyLayoutName.string());
}
}
String8 keyCharacterMapName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
keyCharacterMapName)) {
status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard character "
"map '%s' but it was not found.",
deviceIdenfifier.name.string(), keyLayoutName.string());
}
}
if (isComplete()) {
return OK;
}
}
// Try searching by device identifier.
if (probeKeyMap(deviceIdenfifier, String8::empty())) {
return OK;
}
// Fall back on the Generic key map.
// TODO Apply some additional heuristics here to figure out what kind of
// generic key map to use (US English, etc.) for typical external keyboards.
if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
return OK;
}
// Try the Virtual key map as a last resort.
if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
return OK;
}
// Give up!
ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
deviceIdenfifier.name.string());
return NAME_NOT_FOUND;
}
3.1 InputDeviceIdentifierのnameに一致するklファイルが見つかりません.オリジナルのGenericを使用します.klファイルの1つ目は、InputDeviceIdentifierのnameに一致するklファイルが見つからないことです.この場合、Generalを使用します.klファイルの代わりに.次にprobeKeyMap関数を直接見てみましょう.
bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
const String8& keyMapName) {
if (!haveKeyLayout()) {// kl
loadKeyLayout(deviceIdentifier, keyMapName);
}
if (!haveKeyCharacterMap()) {// kcm
loadKeyCharacterMap(deviceIdentifier, keyMapName);
}
return isComplete();
}
まずisComplete関数を見てみましょう.klファイルとkcmファイルがあってからtrueを返します.load関数を見てください.isCompleteがtrueを返すと、klとkcmファイルが見つかったので、直接returnします.
inline bool isComplete() const {
return haveKeyLayout() && haveKeyCharacterMap();
}
次にklファイルをロードするプロセスを見てみましょう.kcmファイルのロードプロセスはklと似ています.私たちは見ません.
status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
const String8& name) {
String8 path(getPath(deviceIdentifier, name,
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
if (path.isEmpty()) {
return NAME_NOT_FOUND;
}
ALOGE("loadKeyLayout path '%s'.",
path.string());
status_t status = KeyLayoutMap::load(path, &keyLayoutMap);
if (status) {
return status;
}
keyLayoutFile.setTo(path);
return OK;
}
まずgetPath関数を見てみると、load関数でloadKeyLayoutを呼び出した最初のnameは空なので、ここではg e t I n p u t D e v e C o n f i g u rationFilePathByDeviceIdentifiier関数を使用します.
String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
const String8& name, InputDeviceConfigurationFileType type) {
return name.isEmpty()
? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
: getInputDeviceConfigurationFilePathByName(name, type);
}
g e t I n p u t D i c e C o n f i g u r a t i o n F i l e PathByDeviceIdentifiier関数を見てみると、最初の部分は各種Vendorのようなklで、私たちはこの分岐に入っていません.
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 , idc , kl
[cpp] view plain copy
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.string());
if (!access(path.string(), R_OK)) {
ALOGD("Found");
return path;
}
// Search user repository.
// TODO Should only look here if not in safe mode.
path.setTo(getenv("ANDROID_DATA"));
path.append("/system/devices/");
appendInputDeviceConfigurationFileRelativePath(path, name, type);
ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
if (!access(path.string(), R_OK)) {
ALOGD("Found");
return path;
}
// Not found.
ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
name.string(), type);
return String8();
}
以前私たちのロゴでは、このnameがcomipです.snd_soc Headsetも、見つからなかった.
EventHub: name: "comip_snd_soc Headset"
デバイスにどのklファイルがあるか見てみましょう.確かにcomipがありません.snd_soc Headsetというファイル.
AVRCP.kl
Generic.kl
Vendor_0079_Product_0011.kl
Vendor_045e_Product_028e.kl
Vendor_046d_Product_b501.kl
Vendor_046d_Product_c216.kl
Vendor_046d_Product_c219.kl
Vendor_046d_Product_c21d.kl
Vendor_046d_Product_c21f.kl
Vendor_046d_Product_c294.kl
Vendor_046d_Product_c299.kl
Vendor_046d_Product_c532.kl
Vendor_054c_Product_0268.kl
Vendor_0583_Product_2060.kl
Vendor_05ac_Product_0239.kl
Vendor_0b05_Product_4500.kl
Vendor_1038_Product_1412.kl
Vendor_12bd_Product_d015.kl
Vendor_1532_Product_0900.kl
Vendor_1689_Product_fd00.kl
Vendor_1689_Product_fd01.kl
Vendor_1689_Product_fe00.kl
Vendor_18d1_Product_2c40.kl
Vendor_18d1_Product_5018.kl
Vendor_1949_Product_0401.kl
Vendor_1bad_Product_f016.kl
Vendor_1bad_Product_f023.kl
Vendor_1bad_Product_f027.kl
Vendor_1bad_Product_f036.kl
Vendor_1d79_Product_0009.kl
Vendor_22b8_Product_093d.kl
Vendor_2378_Product_1008.kl
Vendor_2378_Product_100a.kl
comip-gpio-keys.kl
comip-keypad.kl
ft5x06.kl
h2w_headset.kl
qwerty.kl
sensor00fn11.kl
振り返ってみるとload関数が呼び出した2番目のprobeKeyMap関数はGenericパラメータに渡されたもので、
if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
return OK;
}
probeKeyMap関数を見てみましょうか、loadKeyLayout関数を呼び出しましたか.
bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
const String8& keyMapName) {
if (!haveKeyLayout()) {
loadKeyLayout(deviceIdentifier, keyMapName);
}
if (!haveKeyCharacterMap()) {
loadKeyCharacterMap(deviceIdentifier, keyMapName);
}
return isComplete();
}
status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
const String8& name) {
String8 path(getPath(deviceIdentifier, name,
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
if (path.isEmpty()) {
return NAME_NOT_FOUND;
}
ALOGE("kangchen loadKeyLayout path '%s'.",
path.string());
status_t status = KeyLayoutMap::load(path, &keyLayoutMap);
if (status) {
return status;
}
keyLayoutFile.setTo(path);
return OK;
}
同様にgetPath関数を見てみましょう.このときnameは空ではありません.getInputDeviceConfigurationFilePathByName関数を呼び出します.
String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
const String8& name, InputDeviceConfigurationFileType type) {
return name.isEmpty()
? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
: getInputDeviceConfigurationFilePathByName(name, type);
}
G e t I n p u t D i c e C o n f i g u rationFilePathByName関数は、最後にこの関数でGenericを見つけた.klファイル.
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.string());
if (!access(path.string(), R_OK)) {
ALOGD("Found");
return path;
}
// Search user repository.
// TODO Should only look here if not in safe mode.
path.setTo(getenv("ANDROID_DATA"));
path.append("/system/devices/");
appendInputDeviceConfigurationFileRelativePath(path, name, type);
ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
if (!access(path.string(), R_OK)) {
ALOGD("Found");
return path;
}
// Not found.
ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
name.string(), type);
return String8();
}
klファイルを見つけたら、このファイルをload関数で解析します.これは分析しません.スキャンコードをキーコードに変換するなどです.
status_t KeyLayoutMap::load(const String8& filename, sp* outMap) {
outMap->clear();
Tokenizer* tokenizer;
status_t status = Tokenizer::open(filename, &tokenizer);
if (status) {
ALOGE("Error %d opening key layout map file %s.", status, filename.string());
} else {
sp map = new KeyLayoutMap();
if (!map.get()) {
ALOGE("Error allocating key layout map.");
status = NO_MEMORY;
} else {
#if DEBUG_PARSER_PERFORMANCE
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
Parser parser(map.get(), tokenizer);
status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
tokenizer->getFilename().string(), tokenizer->getLineNumber(),
elapsedTime / 1000000.0);
#endif
if (!status) {
*outMap = map;
}
}
delete tokenizer;
}
return status;
}
, 。
[plain] view plain copy
key 113 VOLUME_MUTE
key 114 VOLUME_DOWN
key 115 VOLUME_UP
key 116 POWER
kl 。 log
[plain] view plain copy
InputDevice: Probing for system provided input device configuration file: path='/system/usr/keylayout/comip_snd_soc_Headset.kl'
InputDevice: Probing for system user input device configuration file: path='/data/system/devices/keylayout/comip_snd_soc_Headset.kl'
InputDevice: Probe failed to find input device configuration file: name='comip_snd_soc Headset', type=1
InputDevice: Probing for system provided input device configuration file: path='/system/usr/keychars/comip_snd_soc_Headset.kcm'
InputDevice: Probing for system user input device configuration file: path='/data/system/devices/keychars/comip_snd_soc_Headset.kcm'
InputDevice: Probe failed to find input device configuration file: name='comip_snd_soc Headset', type=2
InputDevice: Probing for system provided input device configuration file: path='/system/usr/keylayout/Generic.kl'
InputDevice: Found
Keyboard: loadKeyLayout path '/system/usr/keylayout/Generic.kl'.
InputDevice: Probing for system provided input device configuration file: path='/system/usr/keychars/Generic.kcm'
InputDevice: Found
EventHub: Unable to disable kernel key repeat for /dev/input/event4: Function not implemented
EventHub: New device: id=1, fd=70, path='/dev/input/event4', name='comip_snd_soc Headset', classes=0x81, configuration='', keyLayout='/system/usr/keylayout/Generic.kl', keyCharacterMap='/system/usr/keychars/Generic.kcm', builtinKeyboard=false, wakeMechanism=EPOLLWAKEUP, usingClockIoctl=true
上の例はGenericがロードする.klファイルは、system/usr/keylayoutの下に適切なものが見つからないためです.
3.2 InputDeviceIdentifierに一致するnameを見つけたklファイルの次の例は適切なklファイルを見つけたもので、logを見てみましょう.nameはft 5 x 06であることに注意してください.
EventHub: Opening device: /dev/input/event3
EventHub: Created descriptor: raw=:0000:0000:name:ft5x06, cooked=f2706364e2849110ed562db0c53423b5027a6cc5
EventHub: add device 2: /dev/input/event3
EventHub: bus: 0000
EventHub: vendor 0000
EventHub: product 0000
EventHub: version 0000
EventHub: name: "ft5x06"
EventHub: location: ""
EventHub: unique id: ""
EventHub: descriptor: "f2706364e2849110ed562db0c53423b5027a6cc5"
EventHub: driver: v1.0.1
InputDevice: Probing for system provided input device configuration file: path='/system/usr/idc/ft5x06.idc'
InputDevice: Probing for system user input device configuration file: path='/data/system/devices/idc/ft5x06.idc'
InputDevice: Probe failed to find input device configuration file: name='ft5x06', type=0
EventHub: No input device configuration file found for device 'ft5x06'.
InputDevice: Probing for system provided input device configuration file: path='/system/usr/keylayout/ft5x06.kl'
InputDevice: Found
Keyboard: loadKeyLayout path '/system/usr/keylayout/ft5x06.kl'.
InputDevice: Probing for system provided input device configuration file: path='/system/usr/keychars/ft5x06.kcm'
InputDevice: Probing for system user input device configuration file: path='/data/system/devices/keychars/ft5x06.kcm'
InputDevice: Probe failed to find input device configuration file: name='ft5x06', type=2
InputDevice: Probing for system provided input device configuration file: path='/system/usr/keychars/Generic.kcm'
InputDevice: Found
EventHub: Unable to disable kernel key repeat for /dev/input/event3: Function not implemented
EventHub: New device: id=2, fd=71, path='/dev/input/event3', name='ft5x06', classes=0x15, configuration='', keyLayout='/system/usr/keylayout/ft5x06.kl', keyCharacterMap='/system/usr/keychars/Generic.kcm', builtinKeyboard=false, wakeMechanism=EPOLLWAKEUP, usingClockIoctl=true
デバイスのklファイルを見てみましょう.ft 5 x 06があります.klファイル、これで一致するklファイルが見つかり、元のGenericではありません.klです.
AVRCP.kl
Generic.kl
Vendor_0079_Product_0011.kl
Vendor_045e_Product_028e.kl
Vendor_046d_Product_b501.kl
Vendor_046d_Product_c216.kl
Vendor_046d_Product_c219.kl
Vendor_046d_Product_c21d.kl
Vendor_046d_Product_c21f.kl
Vendor_046d_Product_c294.kl
Vendor_046d_Product_c299.kl
Vendor_046d_Product_c532.kl
Vendor_054c_Product_0268.kl
Vendor_0583_Product_2060.kl
Vendor_05ac_Product_0239.kl
Vendor_0b05_Product_4500.kl
Vendor_1038_Product_1412.kl
Vendor_12bd_Product_d015.kl
Vendor_1532_Product_0900.kl
Vendor_1689_Product_fd00.kl
Vendor_1689_Product_fd01.kl
Vendor_1689_Product_fe00.kl
Vendor_18d1_Product_2c40.kl
Vendor_18d1_Product_5018.kl
Vendor_1949_Product_0401.kl
Vendor_1bad_Product_f016.kl
Vendor_1bad_Product_f023.kl
Vendor_1bad_Product_f027.kl
Vendor_1bad_Product_f036.kl
Vendor_1d79_Product_0009.kl
Vendor_22b8_Product_093d.kl
Vendor_2378_Product_1008.kl
Vendor_2378_Product_100a.kl
comip-gpio-keys.kl
comip-keypad.kl
ft5x06.kl
h2w_headset.kl
qwerty.kl
sensor00fn11.kl
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EV_KEY: {
int32_t scanCode = rawEvent->code;
int32_t usageCode = mCurrentHidUsage;
mCurrentHidUsage = 0;
if (isKeyboardOrGamepadKey(scanCode)) {
int32_t keyCode;
uint32_t flags;
if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {//
keyCode = AKEYCODE_UNKNOWN;
flags = 0;
}
processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
}
break;
}
case EV_MSC: {
if (rawEvent->code == MSC_SCAN) {
mCurrentHidUsage = rawEvent->value;
}
break;
}
case EV_SYN: {
if (rawEvent->code == SYN_REPORT) {
mCurrentHidUsage = 0;
}
}
}
}
processKey , InputDispatch 。 。
mapKey , kcm, kl 。
[cpp] view plain copy
status_t EventHub::mapKey(int32_t deviceId,
int32_t scanCode, int32_t usageCode, int32_t metaState,
int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
status_t status = NAME_NOT_FOUND;
if (device) {
// Check the key character map first.
sp kcm = device->getKeyCharacterMap();
if (kcm != NULL) {
if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
*outFlags = 0;
status = NO_ERROR;
}
}
// Check the key layout next.
if (status != NO_ERROR && device->keyMap.haveKeyLayout()) {
if (!device->keyMap.keyLayoutMap->mapKey(
scanCode, usageCode, outKeycode, outFlags)) {
status = NO_ERROR;
}
}
if (status == NO_ERROR) {
if (kcm != NULL) {
kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState);
} else {
*outMetaState = metaState;
}
}
}
if (status != NO_ERROR) {
*outKeycode = 0;
*outFlags = 0;
*outMetaState = metaState;
}
return status;
}
詳しくkcmのmapKeyとklのmapKeyを分析して後で分析しました