对input系统在framework层的分析从一次触摸屏丢失上报事件开始:由于设备节点/dev/input/input0存在,而且getevent能响应点触摸屏的动作,所以把问题定位到了EventHub和InputManager这一层。
InputManager的结构很简单,对外开放
virtual status_t start();
virtual status_t stop();
virtual sp<InputReaderInterface> getReader();
virtual sp<InputDispatcherInterface> getDispatcher();
四个成员函数,内部带有私有成员
sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
sp<InputDispatcherInterface> mDispatcher;
sp<InputDispatcherThread> mDispatcherThread;
其构造过程也很简单:
mDispatcher = new InputDispatcher(dispatcherPolicy); -- 根据输入的参数构造一个dispatcher
mReader = new InputReader(eventHub, readerPolicy, mDispatcher); -- 根据参数构造一个inputreader
initialize();
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader); -- 产生reader线程用于从设备节点读取input event
mDispatcherThread = new InputDispatcherThread(mDispatcher); -- 产生dispachter线程分发event
}
InputManager的start主要就是让这两个线程跑起来:
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
...
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
...
return OK;
}
====================================================================================================================
接着先来分析InputReader:
InputReaderThread run之后会重复的调用
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
亦即mReader->loopOnce();
void InputReader::loopOnce() {
RawEvent rawEvent;
mEventHub->getEvent(& rawEvent);
process(& rawEvent);
}
InputReader上来就找EventHub要数据(getEvent()),所以我们要先看看EventHub的getEvent都做了些什么工作:
bool EventHub::getEvent(RawEvent* outEvent)
{
outEvent->deviceId = 0;
...
// 第一次调用getEvent的时候,需要调用openPlatformInput来搜索输入系统来查找可用的设备
if (!mOpened) {
mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
mOpened = true;
mNeedToSendFinishedDeviceScan = true;
}
}
bool EventHub::openPlatformInput(void)
{
// 为poll()调用作准备
mFDCount = 1;
mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
mFDs[0].events = POLLIN;
mFDs[0].revents = 0;
mDevices[0] = NULL;
...
// 上面有赋值device_path = "/dev/input"
res = scanDir(device_path);
...
return true;
}
int EventHub::openDevice(const char *deviceName) {
int version;
int fd;
struct pollfd *new_mFDs;
device_t **new_devices;
char **new_device_names;
char name[80];
char location[80];
char idstr[80];
struct input_id id;
LOGV("Opening device: %s", deviceName);
AutoMutex _l(mLock);
// 根据路径打开文件获取version, id, name等信息
fd = open(deviceName, O_RDWR);
if(fd < 0) ...
if(ioctl(fd, EVIOCGVERSION, &version))
...
if(ioctl(fd, EVIOCGID, &id))
...
if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1)
...
// check to see if the device is on our excluded list - 如果此设备在排除名单内,忽略它
List<String8>::iterator iter = mExcludedDevices.begin();
List<String8>::iterator end = mExcludedDevices.end();
for ( ; iter != end; iter++) {
...
}
// 读取location, idstr等信息
if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1)
...
if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1)
...
// 将设备文件设置为非阻塞
if (fcntl(fd, F_SETFL, O_NONBLOCK))
...
// 在mDeviceById数组中寻找“空位”,扩充mDeviceById的空间并把新device加到尾部
int devid = 0;
while (devid < mNumDevicesById) {
if (mDevicesById[devid].device == NULL) {
break;
}
devid++;
}
if (devid >= mNumDevicesById) {
device_ent* new_devids = (device_ent*)realloc(mDevicesById,
sizeof(mDevicesById[0]) * (devid + 1));
if (new_devids == NULL) {
LOGE("out of memory");
return -1;
}
mDevicesById = new_devids;
mNumDevicesById = devid+1;
mDevicesById[devid].device = NULL;
mDevicesById[devid].seq = 0;
}
mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
if (mDevicesById[devid].seq == 0) {
mDevicesById[devid].seq = 1<<SEQ_SHIFT;
}
// 为后面用poll()来获取kernel层上报的input event作准备
new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
if (new_mFDs == NULL || new_devices == NULL) {
LOGE("out of memory");
return -1;
}
mFDs = new_mFDs;
mDevices = new_devices;
device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
if (device == NULL) {
LOGE("out of memory");
return -1;
}
device->fd = fd;
mFDs[mFDCount].fd = fd;
mFDs[mFDCount].events = POLLIN;
mFDs[mFDCount].revents = 0;
// Figure out the kinds of events the device reports.
// 分辨本device的输入类型: keypad? touchscreen? gamepad?
uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
memset(key_bitmask, 0, sizeof(key_bitmask));
// 测试本device是否为键盘,是的话把key_bitmask保存下来
LOGV("Getting keys...");
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
...
}
// 是否为轨迹球或鼠标
// See if this is a trackball (or mouse).
if (test_bit(BTN_MOUSE, key_bitmask)) {
...
}
// 是否为touchscreen,是否支持多点触摸
// See if this is a touch pad.
uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];
memset(abs_bitmask, 0, sizeof(abs_bitmask));
LOGV("Getting absolute controllers...");
if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {
...
}
#ifdef EV_SW
// 是否为switch设备,这个宏没有打开
#endif
// 如果是键盘的话,加载keypad-layout,即/usr/keylayout/中的xxx.kl文件
if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
...
status_t status = device->layoutMap->load(keylayoutFilename);
if (status) {
LOGE("Error %d loading key layout.", status);
}
...
// tell the world about the devname (the descriptive name) - 找一个首选keyboard出来
if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
// the built-in keyboard has a well-known device ID of 0,
// this device better not go away.
mHaveFirstKeyboard = true;
mFirstKeyboardId = device->id;
property_set("hw.keyboards.0.devname", name);
} else {
// ensure mFirstKeyboardId is set to -something-.
if (mFirstKeyboardId == 0) {
mFirstKeyboardId = device->id;
}
}
// 如果键盘有数字键,方向键,游戏控制键等特殊按钮,都一一标记到classes中
if (hasKeycodeLocked(device, AKEYCODE_Q))
...
if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
device->classes |= INPUT_DEVICE_CLASS_DPAD;
}
// See if this device has a gamepad.
for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
break;
}
}
LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
device->id, name, propName, keylayoutFilename);
}
// 如果不知道这个device是啥类型,忽略之
if (device->classes == 0) {
...
}
// 加到mDevicesById和mOpeningDevices中,回头getEvent()会处理mOpenningDevices链表中的新增device
mDevicesById[devid].device = device;
device->next = mOpeningDevices;
mOpeningDevices = device;
mDevices[mFDCount] = device;
mFDCount++;
return 0;
}
bool EventHub::getEvent(RawEvent* outEvent)
{
....
// main loop here - 主循环体
for (;;) {
// Report any devices that had last been removed. - 当有设备从系统中移除时
if (mClosingDevices != NULL) {
...
}
// Report any devices that had last been added - 当有设备加入到系统中时
if (mOpeningDevices != NULL) {
device_t* device = mOpeningDevices;
LOGV("Reporting device opened: id=0x%x, name=%s\n",
device->id, device->path.string());
mOpeningDevices = device->next;
if (device->id == mFirstKeyboardId) {
outEvent->deviceId = 0;
} else {
outEvent->deviceId = device->id;
}
outEvent->type = DEVICE_ADDED;
outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
mNeedToSendFinishedDeviceScan = true;
return true; // 一个设备上报一个DEVICE_ADDED事件
}
// After finish scanning all input devices in system, send finished siganal at boot time
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
outEvent->type = FINISHED_DEVICE_SCAN;
outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
return true;
}
// 下面为普通event获取和上报过程
... ...
}
}
从上面的代码段可知,对于mOpeningDevices中的device,getEvent()调用都是每读取一个马上上报DEVICE_ADDED事件并返回。所以如果我们的系统中有一个keypad和一个touchscreen,则在扫描阶段就会有3次getEvent()返回:键盘的DEVICE_ADDED,触摸屏的DEVICE_ADDED和表示扫描完成的FINISHED_DEVICE_SCAN。