Android Input系统3 InputReader线程
作者:互联网
一 InputReader起点
上一篇文章Android Input系统2 输入系统启动,介绍IMS服务的启动过程会创建两个native线程,分别是InputReader,InputDispatcher. 接下来从InputReader线程的执行过程从threadLoop为起点开始分析。
1.1 threadLoop
InputReader.cpp
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
threadLoop返回值true代表的是会不断地循环调用loopOnce()。另外,如果当返回值为false则会 退出循环。整个过程是不断循环的地调用InputReader的loopOnce()方法,先来回顾一下InputReader对象构造方法。
1.2 loopOnce
InputReader.cpp
void InputReader::loopOnce() {
...
{
AutoMutex _l(mLock);
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
timeoutMillis = 0;
...
} else if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
}
//从EventHub读取事件,其中EVENT_BUFFER_SIZE = 256【见小节2.1】
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) { //处理事件【见小节3.1】
processEventsLocked(mEventBuffer, count);
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
...
} // release lock
if (inputDevicesChanged) { //输入设备发生改变
mPolicy->notifyInputDevicesChanged(inputDevices);
}
//发送事件到nputDispatcher【见小节4.1】
mQueuedListener->flush();
}
二 EventHub
2.1 getEvents
EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
AutoMutex _l(mLock); //加锁
struct input_event readBuffer[bufferSize];
RawEvent* event = buffer; //原始事件
size_t capacity = bufferSize; //容量大小为256
bool awoken = false;
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
...
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked(); //扫描设备【见小节2.2】
mNeedToSendFinishedDeviceScan = true;
}
while (mOpeningDevices != NULL) {
Device* device = mOpeningDevices;
mOpeningDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
event->type = DEVICE_ADDED; //添加设备的事件
event += 1;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break;
}
}
...
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
//从mPendingEventItems读取事件项
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
...
//获取设备ID所对应的device
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
//从设备不断读取事件,放入到readBuffer
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
deviceChanged = true;
closeDeviceLocked(device);//设备已被移除则执行关闭操作
} else if (readSize < 0) {
...
} else if ((readSize % sizeof(struct input_event)) != 0) {
...
} else {
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
//获取readBuffer的数据
struct input_event& iev = readBuffer[i];
//将input_event信息, 封装成RawEvent
event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
+ nsecs_t(iev.time.tv_usec) * 1000LL;
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
if (capacity == 0) {
mPendingEventIndex -= 1;
break;
}
}
}
...
}
...
mLock.unlock(); //poll之前先释放锁
//等待input事件的到来
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
...
mLock.lock(); //poll之后再次请求锁
if (pollResult < 0) { //出现错误
mPendingEventCount = 0;
if (errno != EINTR) {
usleep(100000); //系统发生错误则休眠1s
}
} else {
mPendingEventCount = size_t(pollResult);
}
}
return event - buffer; //返回所读取的事件个数
}
EventHub采用INotify + epoll机制实现监听目录/dev/input下的设备节点,经过EventHub将input_event结构体 + deviceId 转换成RawEvent结构体,如下:
2.1.1 RawEvent
InputEventReader.h
struct input_event {
struct timeval time; //事件发生的时间点
__u16 type;
__u16 code;
__s32 value;
};
struct RawEvent {
nsecs_t when; //事件发生的时间店
int32_t deviceId; //产生事件的设备Id
int32_t type; // 事件类型
int32_t code;
int32_t value;
};
此处事件类型:
- DEVICE_ADDED(添加)
- DEVICE_REMOVED(删除)
- FINISHED_DEVICE_SCAN(扫描完成)
- type<FIRST_SYNTHETIC_EVENT(其他事件)
getEvents()已完成转换事件转换工作, 接下来,顺便看看设备扫描过程。
2.2 设备扫描
2.2.1 scanDevicesLocked
void EventHub::scanDevicesLocked() {
//此处DEVICE_PATH="/dev/input"【见小节2.3】
status_t res = scanDirLocked(DEVICE_PATH);
...
}
2.2.2 scanDirLocked
status_t EventHub::scanDirLocked(const char *dirname)
{
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
//读取/dev/input/目录下所有的设备节点
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);
//打开相应的设备节点【2.2.3】
openDeviceLocked(devname);
}
closedir(dir);
return 0;
}
2.2.3 openDeviceLocked
status_t EventHub::openDeviceLocked(const char *devicePath) {
char buffer[80];
//打开设备文件
int fd = open(devicePath, O_RDWR | O_CLOEXEC);
InputDeviceIdentifier identifier;
//获取设备名
if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1){
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name.setTo(buffer);
}
identifier.bus = inputId.bustype;
identifier.product = inputId.product;
identifier.vendor = inputId.vendor;
identifier.version = inputId.version;
//获取设备物理地址
if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.location.setTo(buffer);
}
//获取设备唯一ID
if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.uniqueId.setTo(buffer);
}
//将identifier信息填充到fd
assignDescriptorLocked(identifier);
//设置fd为非阻塞方式
fcntl(fd, F_SETFL, O_NONBLOCK);
//获取设备ID,分配设备对象内存
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
...
//注册epoll
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
if (mUsingEpollWakeup) {
eventItem.events |= EPOLLWAKEUP;
}
eventItem.data.u32 = deviceId;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
delete device; //添加失败则删除该设备
return -1;
}
...
//【见小节2.2.4】
addDeviceLocked(device);
}
2.2.4 addDeviceLocked
void EventHub::addDeviceLocked(Device* device) {
mDevices.add(device->id, device); //添加到mDevices队列
device->next = mOpeningDevices;
mOpeningDevices = device;
}
介绍了EventHub从设备节点获取事件的流程,当收到事件后接下里便开始处理事件。
三 InputReader
3.1 processEventsLocked
InputReader.cpp
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1; //同一设备的事件打包处理
}
//数据事件的处理【见小节3.3】
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
//设备添加【见小节3.2】
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
//设备移除
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
//设备扫描完成
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false);//不会发生
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
事件处理总共有下几类类型:
DEVICE_ADDED(设备增加), [见小节3.2]
DEVICE_REMOVED(设备移除)
FINISHED_DEVICE_SCAN(设备扫描完成)
数据事件[见小节3.4]
先来说说DEVICE_ADDED设备增加的过程。
3.2 设备增加
3.2.1 addDeviceLocked
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex >= 0) {
return; //已添加的相同设备则不再添加
}
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
uint32_t classes = mEventHub->getDeviceClasses(deviceId);
int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
//【见小节3.2.2】
InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
device->configure(when, &mConfig, 0);
device->reset(when);
mDevices.add(deviceId, device); //添加设备到mDevices
...
}
3.2.2 createDeviceLocked
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
const InputDeviceIdentifier& identifier, uint32_t classes) {
//创建InputDevice对象
InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
controllerNumber, identifier, classes);
...
//获取键盘源类型
uint32_t keyboardSource = 0;
int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
keyboardSource |= AINPUT_SOURCE_KEYBOARD;
}
if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
}
if (classes & INPUT_DEVICE_CLASS_DPAD) {
keyboardSource |= AINPUT_SOURCE_DPAD;
}
if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
keyboardSource |= AINPUT_SOURCE_GAMEPAD;
}
//添加键盘类设备InputMapper
if (keyboardSource != 0) {
device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
}
//添加鼠标类设备InputMapper
if (classes & INPUT_DEVICE_CLASS_CURSOR) {
device->addMapper(new CursorInputMapper(device));
}
//添加触摸屏设备InputMapper
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
device->addMapper(new MultiTouchInputMapper(device));
} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
device->addMapper(new SingleTouchInputMapper(device));
}
...
return device;
}
该方法主要功能:
创建InputDevice对象,将InputReader的mContext赋给InputDevice对象所对应的变量
根据设备类型来创建并添加相对应的InputMapper,同时设置mContext.
input设备类型有很多种,以上代码只列举部分常见的设备以及相应的InputMapper:
键盘类设备:KeyboardInputMapper
触摸屏设备:MultiTouchInputMapper或SingleTouchInputMapper
鼠标类设备:CursorInputMapper
介绍完设备增加过程,继续回到[小节3.1]除了设备的增删,更常见事件便是数据事件,那么接下来介绍数据事件的 处理过程。
3.3 事件处理
3.3.1 processEventsForDeviceLocked
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
...
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
return; //可忽略则直接返回
}
//【见小节3.3.2】
device->process(rawEvents, count);
}
标签:buffer,DEVICE,线程,deviceId,device,Input,Android,event,设备 来源: https://blog.csdn.net/liuwg1226/article/details/113705725