ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android Input系统3 InputReader线程

2021-02-05 23:57:56  阅读:219  来源: 互联网

标签:buffer DEVICE 线程 deviceId device Input Android event 设备


一 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有