【Android休眠】之Android对PowerKey事件的处理(2)EventHub

本文深入探讨了Android系统中EventHub如何处理PowerKey事件,从Linux 3.10到Android 4.4的变化。内容涵盖EventHub在Input事件处理中的角色,包括读取、初步处理和传递事件的流程,以及休眠锁在EventHub中的生命周期。通过对Input设备open流程的分析,揭示了Android如何监控和响应/dev/input/eventX设备节点。
摘要由CSDN通过智能技术生成

Linux 3.10
Android 4.4
http://blog.csdn.net/u013686019/article/details/53691888

一、提纲挈领

EventHub是Android中Input事件的处理中心,完成kernel上报事件的读取、初步处理、传递。

  • 读取:Input设备一旦产生动作,将通过事件(Event)的方式通知user空间;user空间通过读取/dev/input目录下各个文件,获取事件及事件所属的Input设备信息:
  • 初步处理:kernel是以struct input_event的格式上报数据,这里只是根据读取的该结构体做一个简单的封装,成RawEvent形式的数据:

struct input_event {
	struct timeval time;
	__u16 type;
	__u16 code;
	__s32 value;
};

struct RawEvent {
    nsecs_t when;
    int32_t deviceId;
    int32_t type;
    int32_t code;
    int32_t value;
};

传递:RawEvent形式的数据传递给InputReader,由它进一步细分为Android可以识别的数据形式。


二、处理流程


size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    ALOG_ASSERT(bufferSize >= 1);

    AutoMutex _l(mLock);

    struct input_event readBuffer[bufferSize];

    RawEvent* event = buffer;
    size_t capacity = bufferSize;
    bool awoken = false;
	ALOGI("getEvents, enter.");
    for (;;) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

        // 1、mNeedToReopenDevices = false
        if (mNeedToReopenDevices) {
			ALOGI("getEvents, mNeedToReopenDevices.");
            mNeedToReopenDevices = false;

            ALOGI("Reopening all input devices due to a configuration change.");

            closeAllDevicesLocked();
            mNeedToScanDevices = true;
            break; // return to the caller before we actually rescan
        }

        // 2、mClosingDevices == null
        while (mClosingDevices) {
            Device* device = mClosingDevices;
            ALOGI("getEvents, Reporting device closed: id=%d, name=%s\n",
                 device->id, device->path.string());
            mClosingDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
            event->type = DEVICE_REMOVED;
            event += 1;
            delete device;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }

		// 3、EventHub对象构建时设置true
        if (mNeedToScanDevices) {
			ALOGI("getEvents, mNeedToScanDevices.");
            mNeedToScanDevices = false;
			// 4、扫描"/dev/input"目录,若属于我们需要监测的Input设备,就把它加入监测List
			// 详见“Input设备open流程”
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }

		// 5、遍历mOpeningDevices列表,把设备的一些信息打包进RawEvent对象中
        while (mOpeningDevices != NULL) {
            Device* device = mOpeningDevices;
            ALOGW("getEvents, Reporting device opened: id=%d, name=%s\n",
                 device->id, device->path.string());
            mOpeningDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            event->type = DEVICE_ADDED;
            event += 1; // 启动构建下一个RawEvent对象
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }

		// 6、添加一个FINISHED_DEVICE_SCAN类型的RawEvent对象
        if (mNeedToSendFinishedDeviceScan) {
			ALOGW("getEvents, mNeedToSendFinishedDeviceScan.");
            mNeedToSendFinishedDeviceScan = false;
            event->when = now;
            event->type = FINISHED_DEVICE_SCAN;
            event += 1;
            if (--capacity == 0) {
                break;
            }
        }

        // Grab the next input event.
        bool deviceChanged = false;
		ALOGW("getEvents: before while, mPendingEventIndex=%d\n", mPendingEventIndex);
		// 8、有事件,去处理
		// mPendingEventCount:等待处理的事件的个数
		// mPendingEventIndex:指示当前需要处理的事件
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
			ALOGW("getEvents: #1 mPendingEventIndex=%d\n", mPendingEventIndex);
			// EPOLL_ID_INOTIFY:用于监控某个目录(子目录)下是否有新增或者删除文件,在这里用于监视/dev/input
			// 如果有新增设备,则会在该目录内创建新文件;
			// 如果删除设备,则该目录的相应文件会被删除。
            if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
                if (eventItem.events & EPOLLIN) {
                    mPendingINotify = true;
                } else {
                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
                }
                continue;
            }

			// EPOLL_ID_WAKE:EventHub维护一个pipe,当pipe的写入端按照适当格式写入事件后,
			// getEvents可以通过pipe的读取端获取这个虚拟事件
            if (eventItem.data.u32 == EPOLL_ID_WAKE) {
                if (eventItem.events & EPOLLIN) {
                    ALOGV("awoken after wake()");
                    awoken = true;
                    char buffer[16];
                    ssize_t nRead;
                    do {
                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
                    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
                } else {
                    ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
                            eventItem.events);
                }
                continue;
            }

			// 9、当前事件属于的Input设备
            ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
            if (deviceIndex < 0) {
                ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",
                        eventItem.events, eventItem.data.u32);
                continue;
            }

			// 10、获取当前事件属于的Input设备
            Device* device = mDevices.valueAt(deviceIndex);
            if (eventItem.events & EPOLLIN) {
                int32_t readSize = read(device->fd, readBuffer,
                        sizeof(struct input_event) * capacity);
                if (readSize == 0 || (readSize 
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值